Oneblog项目文章间歇性发布失败问题排查
调试
从缓存processorCache中获取socket processor(runnable),并执行

独立的processor线程中处理socket

从recycledProcessors中获取processor,此处的processor包含request信息

recycleProcessors中有什么?
上次被利用后回收的request,如下图,postData还没有回收

Tomcat处理请求

初始化contextHolder,threadlocal中存储request相关信息
这个断点会调用两次,堆栈不一样,未具体研究

进入controller前,获取参数的值
注意,此处parametersParsed如果为true,就会导致解析失败。而他为何是true,请看后面的分析

正常取得参数值

传递参数给Callable对象

将request信息存入threadlocal
注意,此刻线程切换了

保存系统日志
注意,这个方法为async,是由aspect拦截controller的注解实现的,它和request的回收是并行的,也是关键问题所在

此处request还未回收,数据正常

第一个线程开始回收request,并清理threadlocal


真正的原因
asyncSaveSystemLog调用了paresParameters方法,导致已经回收的request的parametersParsed为true,导致下次request请求解析数据失败,controller传值全部为空
所以,实际上不是首次失败,应该是每间隔一次都会失败,当然,犹豫并发的随机性,偶尔连续成功也是有可能的
总之,这种request回收后,接着用,隐患很大,不能这样用。

解决方案
一劳永逸
不要用request,需要的参数,单独拿出来存储在threadlocal.注意,是存储值而非引用,参考克隆。
临时应急
保存日志时,不要用RequestUtil.getParametersMap()

知识点
referring Objects for request 引用request的对象
这个挺有用,使用上,类似mat分析存储一样

正文到此结束