一. 现象:
最近系统定时任务会不定时中断,不是一个任务中断,是全部任务都中断掉,为了数据及时性采取临时解决办法,重启大法!
最近闲下来深入排查了下问题根源,其实网上有许多种解决办法,此篇主要是记录下问题排查思路;
二. 原因分析
1.为什会线程出现中断
原因无外乎几种情况:
死锁(程序编写bug,一旦出现,只能够重启);
数据流操作阻塞挂死;
其实出现这个现象就直接想到是后者(之前遇到过..),心里大概有数是与http请求读取数据时阻塞住了,但是一个定时任务有许多网络请求,哪里出问题了?怎么定位?
2.为什么全部线程都挂死了
一个线程卡死,为什么会导致所有线程卡死?spring 的 @Scheduled定时任务不是并发去执行的吗?
三. 解决
首先第一个问题,既然线程卡死,直接使用jvm提供的命令查看线程状态,定位顶级方法名称,找出卡死的具体代码:
1. 使用命令找出程序pid,方法很多,可自行百度;
ps -ef | grep 'project_name'
2. 使用jvm的jstack命令查询堆栈状态
jstack -l pid | grep '定时任务方法名' ;
这样即可找出具体出现问题堆栈信息,找到具体阻塞方法:笔者这边的核心问题是http在请求的时候没有设置readTimeOut导致流阻塞;后续会继续整理出jvm各个命令的使用;
httpUrlConn.setReadTimeout(30000);
第二个问题,一个线程阻塞住,所有线程为什么会卡死;这个与配置有关; 原配置如下,只配置executor任务执行器,这样线程执行是串行执行,即执行完一个再去执行第二个;
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" >
<property name="corePoolSize" value="10"/>
<property name="maxPoolSize" value="20"/>
<property name="queueCapacity" value="25"/>
<task:annotation-driven executor="taskExecutor"/>
修改后:
<task:executor id="executor" pool-size="10" queue-capacity="10" />
<task:scheduler id="scheduler" pool-size="10"/>
<task:annotation-driven executor="executor" scheduler="scheduler" />
增加调度器,可以配置调度线程池的大小,调度线程在被调度任务完成前不会空闲,具体配置参数可参考官方文档;
如有错误,欢迎指正,大家五一快乐!!