1. 原因
前几天晚上同事突然和我说新开的服务器CPU占用率过高预警
后来经过排查是有个服务的线程长时间占用一颗CPU核心
2. 排查问题
2.1 使用top命令分析线程信息
top -Hp pid
查询到线程ID为18735长时间占用CPU
2.2 保存线程栈信息
jstack pid > /tmp/threadStack.log
2.3 在线程栈中查找线程信息
将线程 18735
转换为十六进制得到 492f
cat /tmp/threadStack.log | grep -A 10 '492f'
找到问题原因是 disruptor
消息队列的 YieldingWaitStrategy
类下的 waitFor
方法的问题 该方法为等待策略方法
粗略的看了下方法内容 应该是为了保持高性能实时性的队列服务所以占用资源过多
3. 解决问题
定位代码
该方法定义了队列服务使用什么等待策略(WaitStrategy
)
[info class=“alert-secondary text-dark”]
Disruptor中使用策略模式定义消费者Consumer处理事件的等待策略,通过com.lmax.disruptor.WaitStrategy接口实现 WaitStrategy等待策略有三种常用的实现: 每种策略具有不同的性能和优缺点.根据实际运行环境的CPU的硬件特点选择恰当的策略,并且使用特定的JVM配置启动参数,能够实现不同的性能提升
策略 | 解释 |
---|---|
BlockingWaitStrategy | 性能最低 对CPU的消耗最小 能够在不同的部署环境中提供更加一致的性能 |
SleepingWaitStrategy | 性能以及对CPU的消耗和BlockingWaitStrategy 差不多对生产者线程影响最小, 适合应用于异步日志等场景 |
YieldingWaitStrategy | 性能最高 适合应用于低延迟的系统 在要求极高的性能并 且事件处理线程个数小于CPU逻辑核心个数的场景中推荐使用这个等待策略 比如CPU开启超线程的特性 |
[/info]
我们将方法修改为即可
@Bean
public Disruptor<PersonalReportEvent> disruptor(){
return new Disruptor<>(PersonalReportEvent::new,
2*1024, DaemonThreadFactory.INSTANCE, ProducerType.SINGLE, new BlockingWaitStrategy());
}
4. 验证
后经测试 YieldingWaitStrategy
策略十二线程 占用9%-10%
后经测试 BlockingWaitStrategy
策略十二线程 占用0%-1%