Appearance
生产问题:线程池打满时怎么排查
线程池问题很典型的一种表现是:
- 请求变慢
- 接口超时
- 日志里开始出现任务拒绝
但线程池打满这件事本身通常不是根因,而是业务执行模型、队列策略、下游慢调用一起暴露出来后的结果。
先说结论
线程池打满时,不要只盯着“线程数够不够”,而要一起看:
- 队列是不是堆满了
- 线程到底在忙什么
- 是任务执行慢,还是下游阻塞
更重要的是先分清:
- 池子满是因为任务太多
- 还是因为任务不释放
- 还是因为一个池子混跑了太多不同类型的任务
一、常见现象
典型现象包括:
- 请求堆积
- 拒绝策略触发
- CPU 可能并不高,但服务已经明显变慢
还经常伴随:
- 接口 RT 飙升
- 异步任务延迟越来越高
- 业务日志出现
RejectedExecutionException - 线程池队列越来越长
二、先看什么
优先确认:
- 核心线程数
- 最大线程数
- 队列长度
- 拒绝策略
很多问题不是线程数太小,而是:
- 无界队列把延迟拖长了
- 下游调用卡住导致线程一直不释放
还要看:
- 活跃线程数是否一直打满
- 已完成任务数有没有明显下降
- 队列是不是只进不出
三、最常见根因
- 数据库连接慢
- 远程接口超时
- 单个任务执行时间过长
- 一个线程池混跑太多不同任务
更具体一些,线上高频根因通常是:
1. 下游阻塞把线程一直占住
任务不是在算,而是在等数据库、Redis、HTTP、MQ、锁。
2. 无界队列掩盖了容量问题
线程数看起来没报错,但队列越积越长,最终整体延迟越来越高。
3. 线程池共用过度
接口请求、批量任务、定时任务、回调任务混在一个池子里,互相拖垮。
4. 拒绝策略没有按业务设计
出了问题后,不是快速失败,而是继续把调用链拖住。
四、怎么处理更稳
通常的方向是:
- 把不同业务类型拆成不同线程池
- 给外部调用加超时
- 队列容量明确设边界
- 拒绝策略明确可控
五、一个更现场化的排查顺序
如果线上已经出现线程池打满,我通常按这个顺序看:
- 先看活跃线程数、队列长度、拒绝次数。
- 看线程到底在忙什么,是执行中还是等待下游。
- 看是不是某个任务类型突然变重或流量变大。
- 看数据库、Redis、HTTP 下游是否同步变慢。
- 最后再决定是拆线程池、降级任务、限流,还是调整容量参数。
这个顺序的重点是先找“为什么线程不释放”,而不是一上来只加线程数。
一句话总结
线程池打满往往不是线程池本身的问题,而是它帮你把下游阻塞、任务过重、队列无边界和容量设计不合理这些问题一起暴露出来了。先看线程在做什么,再看线程池该怎么配,效果通常会更稳。