同一个查询接口,低峰 80ms,高峰涨到 9 秒,线程池活跃数一直等于最大值,队列长度贴着容量上限,任务在队列里平均等 8 秒。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

long start = System.nanoTime();
Future<?> f = pool.submit(task);
log.info("queue wait {} ms", (System.nanoTime() - start) / 1_000_000);

任务不是慢在执行,是慢在排队。线程数固定、队列满,提交方只能等空位,接口耗时里绝大部分是等待时间。这一点先确认清楚,后面就不用反复试。

碰到「队列满延迟激增」这类问题,我习惯先把当前配置原样备份一份,改坏了立刻换回来,不用现场推。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

具体做法是,把排队时间单独打点 和执行时间分开统计;超过阈值的等待直接拒绝 返回可重试错误;按高峰量重算线程数和队列容量;观察 P99 里排队占比是否降到两成以下。

改完照着核一遍,P99 里排队时间低于 200ms,高峰接口耗时回到 300ms 以内。

作者 9823189