本文转载自微信公众号「潜行前行」,优化作者cscw 。排查转载本文请联系潜行前行公众号。线程 1 前天大佬通过prometheus发现 tomcat http busy状态的阻塞线程这几天呈线性递增。每一天增加3个 1:找到busy线程在哪。优化通过jvm自带的排查 jps 命令可以找到服务对应的进程ID:66182$>$top -Hp 66182 $pidstat -u -p 66182 1 5 大部分的线程都正常,cpu利用率不高,线程而且线程ID变动快,阻塞基本排除 死循环、优化CPU 空转的排查问题 2:既然不是死循环、CPU空转。线程那是阻塞不是代码阻塞的问题呢。导出 66182 进程jvm的优化 stack 文件 jstack -l 66182 > block66182.jstack。因为知道是排查http 线程的问题。http 的服务器租用线程开头一般都是 http-nio 。可以使用 grep -A 15 http-nio block66182.jstack 输出一些关键信息。找了很久,多数http 都是正常状态。然后还找到了项目代码 updateXYDVerifiedCodeByDate 之类的。定位到具体,发现是一个定时任务 3 查了下 xxl-task 调度日志。凌晨左右调度了十次,失败了三次,和在prometheus发现的 busy http线程增加的规律是一致的 4 查找代码发现是 CompletableFuture 调用get阻塞住了。后来改成 future.get(15, TimeUnit.SECONDS);。则每隔 15 秒报错一次。但是在promethues 监控到 verifiedCodeQueryExecutor 的线程队列是空的。香港云服务器 4.1 promethues 监控到的线程队列数为空 5 没有任务 CompletableFuture 的get方法还在执行,查看下 verifiedCodeQueryExecutor 的定义。发现,阻塞队列的拒绝策略 是 DiscardPolicy 丢弃。也就是任务丢弃了不被执行,而封装成的CompletableFuture 自然就不会有结果返回,因此一直会被阻塞,而改了代码则是超时返回。真相大白。。。。。 1:队列无限,好像不太好,不接受 2:自定义拒绝策略 3:但考虑到任务必须被处理掉,任务不能被丢弃啊。so 暂时用 CallerRunsPolicy 策略,高防服务器executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 4:后面再优化 问题发现
排查问题
解决问题