一段自旋代码导致CPU飙升至200%!

一段自旋代码导致CPU飙升至200%!

问题引入

项目开发完成后上线,但是只要一启动,不管有没有业务在跑,CPU马上飙升至200%,非常诡异。
在这里插入图片描述

定位原因

首先明确需求,该服务通过自定义的topic创建消费者实例,所以初步判定问题出现在了创建的消费者实例上。

  1. 首先通过top命令查看CPU的占用情况,发现进程已经达到了近200%。
  2. 通过top -H -p 进程号配合jstack发现如果启动两个消费者实例每个就高达100%,启动3个每个达到近70%、4个时每个达到50%、…,反正创建的消费者实例总是要把CPU占满到200%左右。

追踪代码进入公司的组件内,发现了如下的逻辑:

创建消费者实例的部分重要代码如下

public class MqListenerFactory  {
    public void createListener(String topic, String groupId, MessageListener listener) {
    	// ...
        Worker worker = new Worker(topic,listener, messageInterceptor, transportManagerBuilder.getTransportManager(),
                new ConsumerConfig(), null, async);
        worker.setName(topic + "-worker");
        worker.setDaemon(true);
        worker.start();
        if (log.isDebugEnabled()) {
            log.debug("启动MQ监听器,主题:{} 监听器:{}", topic, listener.getClass().getName());
        }
        workerMap.add(topic, worker);
    }
}

Worker的部分重要代码如下

public class Worker extends Thread {
    public void run() {
        // 创建消费者
        createConsumer();
        // 创建线程池
        createExecutor();
        // 开始运行
        running();
    }

	private void running() {
		// ...
        while (messageConsumer.isStarted()) {
            TimeWatch watch = new TimeWatch();
            try {
                String tempPath = messageConsumer.getTransportManager().getConfig().getTempPath();
                // 如果配置了临时文件地址,则是广播模式
                if (!StringUtils.isEmpty(tempPath)){
                    messageConsumer.subscribe(topic,list -> {
                        doListenMessage(list,statistic,watch);
                    });
                }else {
                    messageConsumer.pull(topic, list -> {
                        doListenMessage(list,statistic,watch);
                    });
                }
            } catch (Exception e) {
                log.error("消费消息异常, topic={}, 异常:", topic, e);
            }
        }
        log.warn("已停止拉取消息,请关注!");
        messageConsumer.stop();
        log.warn("已关闭,请关注!");
    }
}

初步判定是因为running方法中的自旋导致

解决

自旋中可以进行适当的睡眠等待,可以让CPU的占用大大下降:Thread.sleep(500)

总结

  • 自旋代码中如果含有I/O、内存操作等的代码,CPU的占用可能不会很高;但是如果类似于上面的纯自旋空转CPU,会导致CPU资源的大量占用。
  • 若场景符合,可以考虑通过加锁替代自旋,以减少CPU资源的过多占用,如上面组件的另一个版本中是通过使用读写锁解决了CPU资源的大量占用。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值