RocketMQ(十二)消息堆积与消费延迟
产生背景
消息处理流程中,如果Consumer的消费速度跟不上Producer的发送速度,MQ中未处理的消息会越来越多,这部分消息就被称为 堆积消息。消息出现堆积会导致消费延迟,以下场景需要重点关注消息堆积和消息延迟的问题。
- 业务系统上下游能力不匹配造成的持续堆积,且无法自行恢复
- 业务系统对消息的消费实时性要求较高,即使是短暂的堆积造成的消费延迟也无法接受。

Consumer使用长轮询Pull模式消费消息时,分为以下两个阶段:
消息拉取
Consumer通过长轮询Pull模式批量拉取的方式从服务端获取消息,将拉取到的消息缓存到本地缓冲队列中。对于拉取式消费,在内网环境下会有很高的吞吐量,所以这一阶段一般不会成为消息堆积的瓶颈。
一个单线程单分区的低规格主机(Consumer,4C8G),其可达到几万的TPS。如果是多个分区多个线程,则可以轻松达到几十万的TPS。
消息消费
Consumer将本地缓存的消息提交到消费线程中,使用业务消费逻辑对消息进行处理,处理完毕后获取到一个结果。这是真正的消息消费过程。此时Consumer的消费能力就完全依赖于消息的消费耗时和消费并发度了。如果由于业务处理逻辑复杂等原因,导致处理单条消息的耗时较长,则整体的消息吞吐量肯定不会高,此时就会导致Consumer本地缓冲队列达到上限,停止从服务端拉取消息。
总结
消息堆积的主要瓶颈在于客户端的消费能力,而消费能力由消费耗时和消费并发度决定。注意,消费耗时的优先级要高于消费并发度。即在保证了消费耗时的合理性前提下,再考虑消费并发度问题。
消费耗时
影响消息处理时长的主要因素是代码逻辑。而代码逻辑中可能会影响处理时长代码主要有两种类型:CPU内部计算型代码和I/O操作型代码。
通常情况下代码中如果没有复杂的递归和循环的话,内部计算耗时相对外部I/O操作来说几乎可以忽略。所以外部IO型代码是消息处理时长变长的主要原因,如:
- 读写远程数据库
- 读写远程Redis
- 对下游系统的http接口调用
关于下游系统调用逻辑需要进行提前梳理,掌握每个调用操作预期的耗时,这样做是为了能够判断消费逻辑中IO操作的耗时是否合理。通常消息堆积是由于下游系统出现了服务异常或达到了DBMS容量限制,导致消费耗时增加。
- 服务异常:也有可能是网络带宽等问题
消息并发度
一般情况下,消费者端的消费并发度由单节点线程数和节点数量共同决定,其值为单节点线程数*节点数量。不过,通常需要优先调整单节点的线程数,若单机硬件资源达到了上限,则需要通过横向扩展来提高消费并发度。
单节点线程数,即单个Consumer所包含的线程数量
节点数量,即Consumer Group所包含的Consumer数量
全局顺序消息:该类型消息的Topic只有一个Queue分区。其可以保证该Topic的所有消息被 顺序消费。为了保证这个全局顺序性,Consumer Group中在同一时刻只能有一个Consumer的一 个线程进行消费。所以其并发度为1。
分区顺序消息:该类型消息的Topic有多个Queue分区。其仅可以保证该Topic的每个Queue 分区中的消息被顺序消费,不能保证整个Topic中消息的顺序消费。为了保证这个分区顺序性, 每个Queue分区中的消息在Consumer Group中的同一时刻只能有一个Consumer的一个线程进行 消费。即,在同一时刻最多会出现多个Queue分蘖有多个Consumer的多个线程并行消费。所以 其并发度为Topic的分区数量。
单机线程数计算
对于一台主

本文探讨了RocketMQ中消息堆积的原因及解决办法,分析了消费耗时与并发度的影响,并介绍了如何通过合理设置避免消息堆积。
最低0.47元/天 解锁文章
1369

被折叠的 条评论
为什么被折叠?



