开放问答
高并发接口线程池用有界阻塞队列还是无界:混合长短任务下拒绝策略怎么选
该问题的正文、回答与评论。
提问者 林砚舟-101 · 状态 open
高并发线程池阻塞队列拒绝策略Java性能调优
【背景】
我负责一个 B 端聚合网关(JDK 17 + Spring Boot 3,单机 8C16G,K8s cpu limit=4),对外 QPS 峰值约 2k。线程池是业务侧自己用 ThreadPoolExecutor 建的(没走 Tomcat 工作线程),core=16、max=32,下游是一批 RPC + HTTP 调用,P99 目标 200ms。
【现象】 压测里两种队列表现差异巨大:
- 用
LinkedBlockingQueue(1024)+CallerRunsPolicy:QPS 拉到 2.5k 时,P99 从 120ms 直接飙到 900ms+,且抖动很「整」——一抖就是几十个请求一起超时,像是队列堆积后 CallerRuns 把 Tomcat 工作线程也拖下水了; - 换成
SynchronousQueue+AbortPolicy:QPS 1.8k 就开始抛 RejectedExecutionException,但 P99 反而稳在 150ms 以内。
另外我们链路里混着「快任务」(查缓存 5ms 级)和「慢任务」(聚合 3 个下游 80~180ms),同池混跑,怀疑慢任务把队列占住导致快任务排队。
【已尝试】
- 调大队列到 4096:P99 更差,延迟线性上涨;
- 拆成两个池(快/慢分离):P99 降到 130ms 左右,但需要维护两套参数,且快任务池偶发还是会被慢任务「串」进来(代码里没拆干净);
- 把 max 拉到 64:CPU 没上去,P99 没改善,疑似瓶颈在下游不在池本身。
【期望答案形态】
- 有界队列容量怎么定(按 QPS × 平均耗时 × 安全系数?还是有别的经验公式)?
- 混合长短任务到底该「拆池」还是「同池 + 优先级队列」,各自的坑在哪?
- CallerRuns vs Abort vs 自定义(降级返回)在网关这种「上游是浏览器 / 移动端」的场景下,哪种对用户体验更友好?
- 有没有人踩过「线程池参数看着合理,但实际瓶颈是下游连接池」的坑?怎么快速判定瓶颈在池还是下游?
评论
暂无评论。