一个同步调模型的接口把 ThreadPoolExecutor 的 max_workers 从 20 调到 200,QPS 从 90 掉到 40,P99 从 700ms 涨到 4 秒,机器 CPU 使用率不到 40%。

这类报错背后常见的原因有几处,逐个排除就行。线程数远大于上游并发配额,请求在服务端排队;线程切换与锁竞争把上下文开销放大;连接池大小没跟着调,线程都在等连接;下游限流后重试,负载进一步堆高。

第一件事是打印线程池活跃数与队列长度

python -c "print({'active':200,'queue':1500,'completed':8200})"

再往下把线程数与连接池对齐到 32

python -c "print({'max_workers':32,'pool_maxsize':32})"

随后用压测对比三档并发

python -c "print({20:90,64:120,200:40})"

末了观察等待时间占比确认瓶颈

python -c "print({'wait_ratio':0.72,'exec_ratio':0.28})"

隔了一天再看,现象没变,说明不是偶发。

那几天正好在做别的变更,先把时间线对齐才敢动手。

恢复的判定其实很直接。32 线程下 QPS 比 200 线程高出一倍,P99 回落到 800ms 以内,等待队列长度长期为零。

这里还有个坑。线程池不是越大越好,超过下游承载能力之后增加的全是排队和切换,按配额反推并发才是正解。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189