每 10 秒出现一次 200 毫秒的接口毛刺,时间点很规律。jstat -gcutil 显示每次毛刺时 YGC 次数没变,GC 日志里没有对应记录,safepoint 日志里能看到 VM_ThreadDump。日志里能对上时间点,这种反而好排。
采集端连 JMX 时调用了 ThreadMXBean.dumpAllThreads,这个操作要求所有线程到达安全点。线程池 300 多个线程全部停下来,等的时间就是毛刺。抓取间隔和采集配置里的 10 秒完全对得上。这一点先确认清楚,后面就不用反复试。
java -Xlog:safepoint=info -jar app.jar jcmd 1 Thread.print -l > /tmp/thread.log jstat -gcutil 1 1000 10
「JMX safepoint 停顿」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。
日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。
处理上按这个顺序:把 dumpAllThreads 换成 getThreadInfo 只取计数 别取堆栈;采集间隔从 10 秒放宽到 60 秒 排查时再临时调;用 safepoint 日志确认停顿来源 别再盲猜 GC;改完连续观察 30 分钟 看毛刺是否消失。
结果对不对很好判断,接口 P99 曲线上的规律毛刺消失,safepoint 日志里不再出现长时间 ThreadDump。
