一、业务表现
在业务容器中,存在如下三个进程:
- JAVA应用进程
- OBProxy进程
- Agent进程
其中Agent进程会启动一个守护线程,定时检查OBproxy进程的状态,如果OBproxy进程挂了,会重新拉起该进程。
现象
业务容器发生OOM,linux OOM killer主动kill掉了OBProxy进程。
Agent的守护线程未按照预期拉起OBproxy进程。
对应Agent简化版代码如下:
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(() -> {
try {
if (obProxyProcessDown) {
pullObProxyProcess();
}
} catch (Exception e) {
//LOG
}
}, 1, 1, TimeUnit.SECONDS);
使用ScheduledExecutorService#scheduleWithFixedDelay定时检查OBproxy进程状态,在OBproxy进程挂掉的情况下主动拉起。
二、原因
如上简化代码,ScheduledExecutorService#scheduleWithFixedDelay里定时任务Task#catch的异常类型是Exception,但是系统OOM那会,抛出的是OOM Error异常,Error > Exception,没Catch住,导致ScheduledExecutorService线程池里的后续任务不执行。
三、复现
OOM后,后续的打印动作并未执行。
四、分析
定时任务执行异常,上面的java.util.concurrent.FutureTask#runAndReset返回false,导致后续的reExecutePeriodic未执行,定时任务没加入到BlockingQueue中,表现就是:后续定时任务不会执行。
具体可以参考:任务异常导致线程池中的线程变为waiting状态