一个同步调模型的接口把 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 以内,等待队列长度长期为零。
这里还有个坑。线程池不是越大越好,超过下游承载能力之后增加的全是排队和切换,按配额反推并发才是正解。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
