JiuyeXD's Blog
九叶
九叶博主

越努力 越幸运

登录
夜间

高性能并发队列Disruptor队列策略占用CPU过高调试笔记

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%

THE END