201207.24.bops操作者id丢失问题排查过程
2012-07-24 14:24
309 查看
背景:
运营反馈在进入页面操作时,修改会员密码等操作会提示操作者id丢失等问题。
代码实现原理:
查看代码,发现是从cookie中获取的操作者id通过log4j的MDC进行上下文传递,写入时正常,但是获取时出现信息丢失。
技术背景:
MDC的实现原理是threadlocal获取上下文,所以在非误操作情况下,在这个线程中的信息是不会丢失的
分析过程:
1.模拟运营操作:发现部分操作成功,部分操作失败;很容易让人联想到是因为个别会员导致的,也是一开始被迷惑了(线上是一个集群),走了不少弯路
2.模拟环境:单独启动一个应用,发现没有失败过,从cookie到MDC的写入以及读出,完全正确,现场无法模拟,实在难以追踪,中断一段时间
后来有位wlb同事刚好搭建了环境,必现这个问题,开始着手排查
3.模拟异常请求:分析请求过程,发现cookie到MDC正常,但是读取失败,想必是代码问题。
4.综上几个,初步定论,该实现与代码部署相关,在特定一些机器下部署,代码不会出现问题且运行正常;但是在其他机器下部署,必然出现问题。
这种问题比较可能是跟类加载有关。
5.分析整体代码结构:
调用点:
![](http://my.csdn.net/uploads/201207/24/1343110054_4248.png)
![](http://my.csdn.net/uploads/201207/24/1343110105_3690.png)
实现:
![](http://my.csdn.net/uploads/201207/24/1343110152_9528.png)
![](http://my.csdn.net/uploads/201207/24/1343110177_5287.png)
说明下:
代码自己封装了jakarta.commons.logging.xxx.jar,getFactory()就是通过jakarta.commons.logging的实现去知道具体的log,然后又由自定义的Logger去包装了一下Log(只包装非log4j实现,MDC依赖log4j)。自己封装logger为了暴露MDC和NDC的接口,至于为什么要这么风封装,这里不深纠了,毕竟代码比较古来。(个人不太喜欢这种封装,完全可以直接用jakarta.commons.logging)。
再来看下getFactory()实现,这个直接关系到具体的代码。网上能找到一些说明,查找具体Factory实现的类,顺序:
读取:commons-logging.properties 的org.apache.commons.logging.LogFactory
系统传入的org.apache.commons.logging.LogFactory属性
类路径下的META-INF/services/org.apache.commons.logging.LogFactory文件
默认实现org.apache.commons.logging.impl.LogFactoryImpl
系统没有传入任何东西,默认是使用的是第三种,分析代码,类似路径的jar包有三个,并且都在war的lib下,具体如下:
META-INF/services/org.apache.commons.logging.LogFactory:
jmemory-1.0-SNAPSHOT.jar
com.alibaba.common.logging.spi.GenericLoggerFactory
toolkit.common.logging-1.0.jar
com.alibaba.common.logging.spi.GenericLoggerFactory
org.slf4j.jcl104-over-slf4j-1.5.6.jar
org.apache.commons.logging.impl.SLF4JLogFactory
前两个还好实现是两套代码,但代码一模一样,咳
但是第三个的实现完全不同,实现是SLF4JLogFactory工厂。
jvm在类加载阶段读取具体的配置,由于lib下读取的顺序是jboss控制,并且和机器有关,导致读取时有些读取到GenericLoggerFactory,产生的log为log4j,能获取到MDC,有些SLF4JLogFactory,产生的log为org.apache.commons.logging.impl.SLF4JLocationAwareLog,该log并非log4j实现,在封装logger时,采用了LoggerWrapper,里面的MDC实现为空实现,导致信息没有记录。
直接诱因:odin引入的
<groupId>com.xxxxx.external</groupId>
<artifactId>org.slf4j.jcl104-over-slf4j</artifactId>
解决:
1.逐出org.slf4j.jcl104-over-slf4j,直接但不彻底
2. bops由于日志系统太多,有log4j(web),slf4j(task),但是包打成一个,在加载时会出现一些不可预期的结果,建议梳理bops。
最好能把MDC全部替换为threadlocal,这样不依赖于任何日志系统,原先的使用方式已经不适合了
运营反馈在进入页面操作时,修改会员密码等操作会提示操作者id丢失等问题。
代码实现原理:
查看代码,发现是从cookie中获取的操作者id通过log4j的MDC进行上下文传递,写入时正常,但是获取时出现信息丢失。
技术背景:
MDC的实现原理是threadlocal获取上下文,所以在非误操作情况下,在这个线程中的信息是不会丢失的
分析过程:
1.模拟运营操作:发现部分操作成功,部分操作失败;很容易让人联想到是因为个别会员导致的,也是一开始被迷惑了(线上是一个集群),走了不少弯路
2.模拟环境:单独启动一个应用,发现没有失败过,从cookie到MDC的写入以及读出,完全正确,现场无法模拟,实在难以追踪,中断一段时间
后来有位wlb同事刚好搭建了环境,必现这个问题,开始着手排查
3.模拟异常请求:分析请求过程,发现cookie到MDC正常,但是读取失败,想必是代码问题。
4.综上几个,初步定论,该实现与代码部署相关,在特定一些机器下部署,代码不会出现问题且运行正常;但是在其他机器下部署,必然出现问题。
这种问题比较可能是跟类加载有关。
5.分析整体代码结构:
调用点:
![](http://my.csdn.net/uploads/201207/24/1343110054_4248.png)
![](http://my.csdn.net/uploads/201207/24/1343110105_3690.png)
实现:
![](http://my.csdn.net/uploads/201207/24/1343110152_9528.png)
![](http://my.csdn.net/uploads/201207/24/1343110177_5287.png)
说明下:
代码自己封装了jakarta.commons.logging.xxx.jar,getFactory()就是通过jakarta.commons.logging的实现去知道具体的log,然后又由自定义的Logger去包装了一下Log(只包装非log4j实现,MDC依赖log4j)。自己封装logger为了暴露MDC和NDC的接口,至于为什么要这么风封装,这里不深纠了,毕竟代码比较古来。(个人不太喜欢这种封装,完全可以直接用jakarta.commons.logging)。
再来看下getFactory()实现,这个直接关系到具体的代码。网上能找到一些说明,查找具体Factory实现的类,顺序:
读取:commons-logging.properties 的org.apache.commons.logging.LogFactory
系统传入的org.apache.commons.logging.LogFactory属性
类路径下的META-INF/services/org.apache.commons.logging.LogFactory文件
默认实现org.apache.commons.logging.impl.LogFactoryImpl
系统没有传入任何东西,默认是使用的是第三种,分析代码,类似路径的jar包有三个,并且都在war的lib下,具体如下:
META-INF/services/org.apache.commons.logging.LogFactory:
jmemory-1.0-SNAPSHOT.jar
com.alibaba.common.logging.spi.GenericLoggerFactory
toolkit.common.logging-1.0.jar
com.alibaba.common.logging.spi.GenericLoggerFactory
org.slf4j.jcl104-over-slf4j-1.5.6.jar
org.apache.commons.logging.impl.SLF4JLogFactory
前两个还好实现是两套代码,但代码一模一样,咳
但是第三个的实现完全不同,实现是SLF4JLogFactory工厂。
jvm在类加载阶段读取具体的配置,由于lib下读取的顺序是jboss控制,并且和机器有关,导致读取时有些读取到GenericLoggerFactory,产生的log为log4j,能获取到MDC,有些SLF4JLogFactory,产生的log为org.apache.commons.logging.impl.SLF4JLocationAwareLog,该log并非log4j实现,在封装logger时,采用了LoggerWrapper,里面的MDC实现为空实现,导致信息没有记录。
直接诱因:odin引入的
<groupId>com.xxxxx.external</groupId>
<artifactId>org.slf4j.jcl104-over-slf4j</artifactId>
解决:
1.逐出org.slf4j.jcl104-over-slf4j,直接但不彻底
2. bops由于日志系统太多,有log4j(web),slf4j(task),但是包打成一个,在加载时会出现一些不可预期的结果,建议梳理bops。
最好能把MDC全部替换为threadlocal,这样不依赖于任何日志系统,原先的使用方式已经不适合了
相关文章推荐
- android开发过程中R.java丢失问题的分析
- MySQL生产库Insert了2次同样的记录但是主键ID是不一样的问题的分 4000 析过程
- MySQL 存储过程传参数问题:实现 where id in(1,2,3,...)
- 问题排查中用到的工具及通用分析过程
- Authid Current_User is解决执行过程中01031权限不足的问题
- MySQL 存储过程传参数问题:实现 where id in(1,2,3,...)
- 某sde问题排查过程
- ILJMALL project过程中遇到Fragment嵌套问题:IllegalArgumentException: Binary XML file line #23: Duplicate id
- 一起C语言中程序时序问题的排查过程
- Spring boot + shiro 跨域配置(解决jsessionid丢失问题)
- 记一次kafka数据丢失问题的排查
- 记一次线上问题的排查过程
- MySQL 存储过程传参数问题:实现 where id in(1,2,3,...)
- 一次CMS GC问题排查过程(理解原理+读懂GC日志)
- 记录一次对代码完全陌生的问题排查过程
- 记一次kafka数据丢失问题的排查
- 两起变量初始化问题的排查过程
- 测试环境mysql参数max_allowed_packet自动更改的问题排查过程
- hdfs块丢失导致的异常问题排查解决
- 软件运行中界面显示异常——GDI资源泄漏问题的排查过程