一次Tomcat假死的问题寻找

运行环境:Linux CentOS 7 JDK8 Tomcat8 MYSQL SpringMVC, 8G内存,Tomcat不定时的假死,假死时GC线程都是接近100%,根据网上排查假死的方法,jstatck、jmap、jvisualVM,MAT都查了个遍,能定位到相关的地方,但是看代码觉得没有任何问题,最好还是加上了MAP、LIST等类型在使用完成后赋值为null,强制为垃圾以便回收,但是没有效果。后来琢磨着假死时还是看下SQL运行语句吧,使用mysql的指令show full processList,发现一条只有日期字段而没有记录数限制的SQL的执行状态是Sending Data,正常而言,该SQL语句的数据不多的,过了几秒后再执行,发现那个语句L的执行状态是Sending Data,估计是这个语句引起的,将该语句复制出来改为统计记录数后执行,发现居然大于150万,就是它了,这里巨量的数据要返回给前端,必死无疑。其实该语句也会出现在druid-slow-sql.log文件中,只是自己没有留意而已。

下面来分析下过程:第一个表:表A是股票交易所的当天分时指数,每个交易所每分钟一条数据,一般而言,一个交易所一天就是几百条记录。第二个表:表B是股票交易所的最近一周的分时指数,当时为了提高当天分时指数的速度,表A只保留一天的数据,由第三方负责插入,表B的数据是本程序每天将表A的数据复制一份到表B,然后清除一周前的数据。从逻辑看起来没问题,问题是在于复制时没有根据当天日期进行复制,而是认为表A的数据就是当天的,所以复制时造成了表B数据的重复,并且表A的数据由于第三方的原因,好久没有更新,这样长期累计下来,在表B中的同一天的数据就很多了。一般情况下,用户不查询周线指数时,系统正常,一旦查询周线指数,必然出现假死,由于这个操作时间的不确定,所以假死是没有规律的。

最后修复方法包括:1)直接在指数查询语句限制记录数,这个可以快速更新代码,就算数据有错,也不至于系统假死而造成系统无法使用;2)修改表B的复制处理逻辑,严格按照当天日期进行。

经过这个事情,得出的结论:1)不要偷懒,代码逻辑要编写严谨;2)不要假设第三方提供的服务和数据不存在问题,你要假设它存在的问题,然后自己提供方法保证不会影响到自己编写的模块功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章