微服务线程数暴涨10倍P0故障排查
从32000线程告警到根治,一次Spring Cloud生产事故复盘 · IT中华技术日记
生产服务器突然告警:创建线程总数超过32000个,服务濒临崩溃。本文复盘一次真实的P0故障,从线程组成分析到逐层治理,给出可直接落地的配置代码。
一、故障现场
某微服务节点线程总数达到 5000+,监控告警提示创建线程总数逼近 32000 上限。服务框架栈如下:
- Spring Boot 2 + Spring Cloud
- 服务间 Feign 调用 + Ribbon + Hystrix
- Undertow 容器 + MyBatis-Plus + Redis + RabbitMQ
- 自定义线程池与 @Async 混用
二、线程组成拆解
一个 Spring Cloud 微服务的线程数大致等于以下各项之和:
Undertow Worker 线程
+ Feign 调用线程池 / HTTP 连接池线程
+ Hystrix 线程池(THREAD 隔离策略)
+ RabbitMQ Listener 线程池
+ Redis 连接池(Lettuce Netty EventLoop)
+ 业务线程池(@Async / 自定义 ThreadPool)
+ Spring 内部线程 + JVM 系统线程
告警时的统计:
- NIO 线程:1000(达到设置上限)
- 普通 thread 线程:2000+(未使用线程池,无限创建)
- Hystrix 线程:3000+(配置未生效)
- 数据库连接、Redis、MQ 线程:少量
三、三大元凶
3.1 Undertow 设置过大
Worker 线程数配到了 1000,而 8 核节点通常 IO 线程 8 个、Worker 线程 512 个已经足够。改成按 CPU 核数配比:
undertow:
threads:
worker: 512 # CPU核数 * 8
io: 8 # CPU核数
buffer-size: 1024
direct-buffers: true
3.2 业务代码未使用线程池
大量异步任务直接用 new Thread() 或默认 @Async,没有线程池兜底,导致线程无限膨胀。正确做法是统一配置 ThreadPoolTaskExecutor:
@EnableAsync
public class ThreadPoolConfig {
@Bean("businessExecutor")
public ThreadPoolTaskExecutor businessExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(200);
executor.setThreadNamePrefix("biz-");
return executor;
}
}
3.3 Hystrix 线程池配置未生效
Hystrix 默认使用 THREAD 隔离策略,每个 Feign Client 都会创建一个独立线程池。如果依赖了 10 个下游服务,默认就会创建 10 个线程池;每个 coreSize=100,仅 Hystrix 一项就能占满 1000 个线程。
threadpool:
default:
coreSize: 10
maxQueueSize: 50
queueSizeRejectionThreshold: 50
base-server: # 可为特定服务单独覆盖
coreSize: 20
maxQueueSize: 100
command:
default:
execution:
isolation:
strategy: THREAD
thread:
timeoutInMilliseconds: 5000
关键认知:hystrix.threadpool.default 是模板,不是全局共享池。每个 Feign Client 都会按这个模板独立初始化自己的线程池。10 个下游服务就是 10 份资源。
四、其他组件配置参考
4.1 Druid 数据源
datasource:
druid:
initial-size: 5
max-active: 20
min-idle: 5
4.2 Redis Lettuce 连接池
redis:
lettuce:
pool:
max-active: 16
max-idle: 8
min-idle: 4
4.3 RabbitMQ Listener
rabbitmq:
listener:
simple:
concurrency: 5
max-concurrency: 20
prefetch: 10
acknowledge-mode: auto
五、IT中华观点
微服务线程问题往往不是某个单点,而是「容器 + RPC + 线程池 + 连接池」层层叠加的结果。排查时要先画出线程组成全景,再按占比从高到低治理。配置时牢记一个原则:没有边界的资源,最终都会变成故障。
关于 IT中华
IT中华(www.itzh.vip)持续记录技术实战与踩坑经验。关注 IT中华,获取更多系统架构、性能排查与自动化实践。
本文转载自博客园并改写,仅供学习交流。