RocketMQ 消息队列冷读问题的分析与优化

时间:2025-09-03 14:30:02来源:互联网

下面小编就为大家分享一篇RocketMQ 消息队列冷读问题的分析与优化,具有很好的参考价值,希望对大家有所帮助。

冷读问题的分析

最近有群里的同学咨询我关于线上RocketMQ集群服务器磁盘IOPS很高,业务方反馈写入延迟增大的问题。这种问题一般情况下都是RocketMQ集群产生冷读造成的,对于RocketMQ来讲,如果消费比较及时,大部分读取仅通过PageCache就完成了,但是冷读的消费者,读取的消息已经从pageCache中被驱逐了,此时消息的读取会从磁盘中读取,会消耗磁盘的带宽和IOPS。还有一点,冷读也会导致读放大,因为当消费者需要读取一条很久远的消息(产生冷读)时,系统必须从磁盘加载一个包含该消息的数据块,但由于数据块内混合存储了其他消息(其他Topic的或者其他队列的),导致实际读取的数据量远大于所需的数据量,从而造成了读放大效应,这种情况下,会挤压pageCache的空间,极端情况下会导致热数据会被置换。

冷读产生的原因

冷读产生的原因肯定是跟消费者相关的,一般来说,消费者是分为两种类型的,第一种是追尾读类型的消费者,一般在实时的消费,消费基本上在cache当中,消费的RT也较短,对系统资源的消耗也很低,另外一种就属于冷读的消费者了。 image.png

产生冷读的原因一个就是消费者的消费速度跟不上生产者的写入速度,导致消息积压。积压的消息因为“太老”,早已从 PageCache 中被淘汰。另一种情况就是访问模式本身决定了要读取的数据不在缓存中,比如新的消费者组启动选择从CONSUME_FROM_FIRST_OFFSET的消费或者需要回溯消费的场景。

image.png

一个consumerQueue存在三种offset,一个是commitOffset 这个是消费者消费完成的位点,一个是pullOffset 这个是消费者正在拉取的位点,最后一个就是maxOffset 这个是这个队列最大可以消费的位点

冷读产生的原因就是pullOffset距离maxOffset太远了,导致这部分数据已经被置换到磁盘了,如果要读取的话,就需要从磁盘上面读取,这个读取是一个强烈的随机读IO,需要消耗磁盘的带宽和IOPS,磁盘现在要同时处理生产者的顺序写入和消费者的随机读取,这就破坏了生产者写入消息的顺序性,会导致写入延迟的增大,从pageCache的角度来看,大量冷读的数据会进入pageCache中,会挤压热数据的生存空间,为了容纳这些新的冷读数据,内核的 kswapd线程会开始回收页面,这可能会淘汰掉那些原本是热数据的消息或者索引,也可能导致后续本应是热读的操作再次变成冷读,形成恶性循环

冷读的处理

硬件方面有如下两点可以来进行优化:

线上遇到这种冷读情况后,若已经对业务造成了很大的影响,可以使用以下的几种处理方式来进行:

本站部分内容转载自互联网,如果有网站内容侵犯了您的权益,可直接联系我们删除,感谢支持!