原创

Oneblog项目文章间歇性发布失败问题排查

调试

从缓存processorCache中获取socket processor(runnable),并执行

img

独立的processor线程中处理socket

img

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

img

recycleProcessors中有什么?

上次被利用后回收的request,如下图,postData还没有回收

img

Tomcat处理请求

img

初始化contextHolder,threadlocal中存储request相关信息

这个断点会调用两次,堆栈不一样,未具体研究

img

进入controller前,获取参数的值

注意,此处parametersParsed如果为true,就会导致解析失败。而他为何是true,请看后面的分析

图形用户界面  描述已自动生成

正常取得参数值

图形用户界面, 文本  描述已自动生成

传递参数给Callable对象

文本  描述已自动生成

将request信息存入threadlocal

注意,此刻线程切换了

文本  描述已自动生成

保存系统日志

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

电脑萤幕的截图  描述已自动生成

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

img

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

图形用户界面, 文本  描述已自动生成

图形用户界面, 文本  描述已自动生成

真正的原因

asyncSaveSystemLog调用了paresParameters方法,导致已经回收的request的parametersParsed为true,导致下次request请求解析数据失败,controller传值全部为空

所以,实际上不是首次失败,应该是每间隔一次都会失败,当然,犹豫并发的随机性,偶尔连续成功也是有可能的

总之,这种request回收后,接着用,隐患很大,不能这样用。

图形用户界面, 文本  描述已自动生成

解决方案

一劳永逸

不要用request,需要的参数,单独拿出来存储在threadlocal.注意,是存储值而非引用,参考克隆。

临时应急

保存日志时,不要用RequestUtil.getParametersMap()

img

知识点

referring Objects for request 引用request的对象

这个挺有用,使用上,类似mat分析存储一样

文本  描述已自动生成

正文到此结束