专业的编程技术博客社区

网站首页 > 博客文章 正文

RocketMQ参数调优--记一次broker busy异常

baijin 2025-07-21 12:34:52 博客文章 3 ℃ 0 评论

MQ大家并不陌生,想必在项目中也是使用的非常多了。不过如此常见的消息中间件,我们很多人包括歪哥基本还停留在只会使用,出现问题并不知如何下手分析。之前歪哥就遇到了生产环境MQ消息丢失问题,下面简单介绍下问题原因及优化历程。

broker busy

事件经过是这样的,流量高峰期,业务首先受到感知,出现大量MQ发送失败情况,报broker busy异常。代码位置定位如下:

可以看到这里是broker端os pageCache busy,RocketMQ消息持久化是先写入page cache中,后由操作系统进行刷盘操作。所以这里是消息写入到cache中时就报错了。总结说,就是broker在处理消息写入page cache持久化的时候系统写繁忙异常。

操作系统判断是否page写入繁忙逻辑如下:

  • 获取CommitLog获取锁的开始时间,因为broker把本机所有topic消息的写入都采用追加到同一个CommitLog中,所以采用锁来进行并发写入的控制。
  • CommitLog中的锁有两种实现形式,ReentrantLock(非公平)和Spin Lock两种形式,默认采用Spin Lock形式,锁的实现比较简单,这里就不进行展开。
  • 计算CommitLog锁持有时间 = 当前时间 - 获取锁开始时间,page cache timeout默认配置的时间是1000ms,也即1s,所以broker在处理上一个消息写入的时候占有锁的时间超过1s的时候就会被认为page cache busy。

在client端发送消息的时候,如果发生了MQBrokerException的时候,获取到broker端返回的response,response code = system_error的时候就continue,同步消息会进行重试两次,异步消息和oneway消息不会进行重试,所以这两种模式在这种情况下就会丢消息。

参数调优

这个时候我们就明白了,既然等待时间超过了阈值,那我们就调整阈值,写入阻塞了我们就多开些线程,按照这样的思路我们就可以着手对MQ参数进行调整。

#系统页面缓存繁忙超时时间(翻译),默认值 1000
osPageCacheBusyTimeOutMills=3000
#发送消息的最大线程数,默认1
sendMessageThreadPoolNums=32

服务端处理写请求默认线程数为1,我们可以调大一些,处理得更快,但具体多少要根据实际情况调整。

调节这两个参数之后,情况有了明显的改善。此外,MQ还有很多其他可调整参数,我们可以了解一些比较重要的。

#主从异步复制
brokerRole=ASYNC_MASTER
#异步刷盘
flushDiskType=ASYNC_FLUSH
#线上关闭自动创建topic
autoCreateTopicEnable=false
 
#使用可重入锁
useReentrantLockWhenPutMessage=true
#发送消息线程等待时间,默认200ms
waitTimeMillsInSendQueue=1000
 
#开启临时存储池
transientStorePoolEnable=true
#开启Slave读权限(分担master 压力)
slaveReadEnable=true
#关闭堆内存数据传输
transferMsgByHeap=false
#开启文件预热
warmMapedFileEnable=true

最后总结一句,参数调优很重要,但最根本的一个原则就是:尽量用多个小集群替代一个大集群。一般初期都是用一个集群,业务越来越庞大之后,就会面临系统风险,着手拆分一定要提上日程。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表