RocketMQ(9) 消息堆积与消费延迟
消息堆积与消费延迟
1 概念
消息处理流程中,如果Consumer的消费速度跟不上Producer的发送速度,MQ中未处理的消息会越来越多(进的多出的少),这部分消息就被称为堆积消息。消息出现堆积进而会造成消息的消费延迟。 以下场景需要重点关注消息堆积和消费延迟问题:
- 业务系统上下游能力不匹配造成的持续堆积,且无法自行恢复。
- 业务系统对消息的消费实时性要求较高,即使是短暂的堆积造成的消费延迟也无法接受。
2 产生原因分析
Consumer使用长轮询Pull模式消费消息时,分为以下两个阶段:
1.消息拉取
Consumer通过长轮询Pull模式批量拉取的方式从服务端获取消息,将拉取到的消息缓存到本地缓冲队列中。对于拉取式消费,在内网环境下会有很高的吞吐量,所以这一阶段一般不会成为消息堆积的瓶颈。
一个单线程单分区的低规格主机(Consumer,4C8G),其可达到几万的TPS。如果是多个分区多 个线程,则可以轻松达到几十万的TPS。
2. 消息消费
Consumer将本地缓存的消息提交到消费线程中,使用业务消费逻辑对消息进行处理,处理完毕后获取 到一个结果。这是真正的消息消费过程。此时Consumer的消费能力就完全依赖于消息的消费耗时和消 费并发度了。
如果由于业务处理逻辑复杂等原因,导致处理单条消息的耗时较长,则整体的消息吞吐量肯定不会高,此时就会导致Consumer本地缓冲队列达到上限,停止从服务端拉取消息。
结论: 消息堆积的主要瓶颈在于客户端的消费能力,而消费能力由消费耗时和消费并发度决定。注意,消费 耗时的优先级要高于消费并发度。即在保证了消费耗时的合理性前提下,再考虑消费并发度问题。
3 消费耗时
影响消息处理时长的主要因素是代码逻辑。而代码逻辑中可能会影响处理时长代码主要有两种类型: CPU内部计算型代码和外部I/O操作型代码。
通常情况下代码中如果没有复杂的递归和循环的话,内部计算耗时相对外部I/O操作来说几乎可以忽略。所以外部IO型代码是影响消息处理时长的主要症结所在。
外部IO操作型代码举例:
读写外部数据库,例如对远程MySQL的访问
读写外部缓存系统, 例如对远程Redis的访问
下游系统调用,例如Dubbo的RPC远程调用,Spring Cloud的对下游系统的Http接口调用
关于下游系统调用逻辑需要进行提前梳理,掌握每个调用操作预期的耗时,这样做是为了能够 判断消费逻辑中IO操作的耗时是否合理。通常消息堆积是由于下游系统出现了服务异常或达到 了DBMS容量限制,导致消费耗时增加。
服务异常,并不仅仅是系统中出现的类似500这样的代码错误,而可能是更加隐蔽的问题。例如,网络带宽问题。
达到了DBMS容量限制,其也会引发消息的消费耗时增加。
4. 消费并发度
一般情况下,消费者端的消费并发度由单节点线程数和节点数量共同决定,其值为单节点线程数*节点数量。
不过,通常需要优先调整单节点的线程数,若单机硬件资源达到了上限,再需要通过横向扩展来提高消费并发度。
单节点线程数,即单个Consumer所包含的线程数量
节点数量,即Consumer Group所包含的Consumer数量
对于普通消息、延时消息及事务消息,并发度计算都是单节点线程数*节点数量。
但对于顺序 消息则是不同的。
顺序消息的消费并发度等于Topic的Queue分区数量。
1)全局顺序消息:该类型消息的Topic只有一个Queue分区(一台机器)。其可以保证该Topic的所有消息被顺序消费。
为了保证这个全局顺序性,Consumer Group中的任何一个机器在同一时刻只能有一个Consumer消费者进行消费。所以其并发度为1。
2)分区顺序消息:该类型消息的Topic有多个Queue分区(一个topic下的queue分布在集群中的多个broker中)。
其仅可以保证该Topic的某台broker的消息被顺序消费,不能保证整个Topic中消息的顺序消费。
为了保证这个分区顺序性, 每个Queue分区中的消息在Consumer Group中的同一时刻只能有一个Consumer的一个线程进行 消费。即,在同一时刻最多会出现多个Queue分蘖有多个Consumer的多个线程并行消费。所以其并发度为Topic的分区数量(该topic的broker分区数量)。
5. 单机线程数计算
对于一台主机中线程池中线程数的设置需要谨慎,不能盲目直接调大线程数,设置过大的线程数反而会
带来大量的线程切换的开销。理想环境下单节点的最优线程数计算模型为:C *(T1 + T2)/ T1。
C:CPU内核数
T1:CPU内部逻辑计算耗时
T2:外部IO操作耗时
最优线程数 = C **(T1 + T2)/ T1 = C * T1/T1 + C * T2/T1 = C + C * T2/T1*
注意,该计算出的数值是理想状态下的理论数据,在生产环境中,不建议直接使用。而是根据
当前环境,先设置一个比该值小的数值然后观察其压测效果,然后再根据效果逐步调大线程
数,直至找到在该环境中性能最佳时的值。
6. 如何避免
为了避免在业务使用时出现非预期的消息堆积和消费延迟问题,需要在前期设计阶段对整个业务逻辑进
行完善的排查和梳理。其中最重要的就是梳理消息的消费耗时和设置消息消费的并发度。
梳理消息的消费耗时
通过压测获取消息的消费耗时,并对耗时较高的操作的代码逻辑进行分析。梳理消息的消费耗时需要关
注以下信息:
- 消息消费逻辑的计算复杂度是否过高,代码是否存在无限循环和递归等缺陷。
- 消息消费逻辑中的I/O操作是否是必须的,能否用本地缓存等方案规避。
- 消费逻辑中的复杂耗时的操作是否可以做异步化处理。如果可以,是否会造成逻辑错乱
设置消费并发度
对于消息消费并发度的计算,可以通过以下两步实施
逐步调大单个Consumer节点的线程数,并观测节点的系统指标,得到单个节点最优的消费线程数
和消息吞吐量。
根据上下游链路的流量峰值计算出需要设置的节点数
节点数 = 流量峰值 / 单个节点消息吞吐量
消息的清理
消息被消费过后会被清理掉吗?不会的。
消息是被顺序存储在commitlog文件的,且消息大小不定长,所以消息的清理是不可能以消息为单位进 行清理的,而是以commitlog文件为单位进行清理的。否则会急剧下降清理效率,并且实现起来逻辑复杂。
commitlog文件存在一个过期时间,默认为72小时,即三天。除了用户手动清理外,在以下情况下也 会被自动清理,无论文件中的消息是否被消费过:
文件过期,且到达清理时间点(默认为凌晨4点)后,自动清理过期文件
文件过期,且磁盘空间占用率已达过期清理警戒线(默认75%)后,无论是否达到清理时间点, 都会自动清理过期文件
磁盘占用率达到清理警戒线(默认85%)后,开始按照设定好的规则清理文件,无论是否过期。 默认会从最老的文件开始清理
磁盘占用率达到系统危险警戒线(默认90%)后,Broker将拒绝消息写入
需要注意以下几点:
1)对于RocketMQ系统来说,删除一个1G大小的文件,是一个压力巨大的IO操作。在删除过程 中,系统性能会骤然下降。所以,其默认清理时间点为凌晨4点,访问量最小的时间。也正因如 果,我们要保障磁盘空间的空闲率,不要使系统出现在其它时间点删除commitlog文件的情况。
2)官方建议RocketMQ服务的Linux文件系统采用ext4。因为对于文件删除操作,ext4要比ext3性 能更好
RocketMQ(9) 消息堆积与消费延迟的更多相关文章
- RocketMQ的消息发送及消费
RocketMQ消息支持的模式: 消息支持的模式分为三种:NormalProducer(普通同步),消息异步发送,OneWay. 消息同步发送: 普通消息的发送和接收在前面已经演示过了,在前面的案例中 ...
- 分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”
在说到消息中间件的时候,我们通常都会谈到一个特性:消息的顺序消费问题.这个问题看起来很简单:Producer发送消息1, 2, 3... Consumer按1, 2, 3...顺序消费. 但实际情况却 ...
- 关于 RocketMQ ClientID 相同引发的消息堆积的问题
首先,造成这个问题的 BUG RocketMQ 官方已经在 3月16号 的这个提交中修复了,这里只是探讨一下在修复之前造成问题的具体细节,更多的上下文可以参考我之前写的 <RocketMQ Co ...
- rocketmq总结(消息的顺序、重复、事务、消费模式)
rocketmq总结(消息的顺序.重复.事务.消费模式) 参考: http://www.cnblogs.com/wxd0108/p/6038543.html https://www.cnblogs.c ...
- 一次 RocketMQ 顺序消费延迟的问题定位
一次 RocketMQ 顺序消费延迟的问题定位 问题背景与现象 昨晚收到了应用报警,发现线上某个业务消费消息延迟了 54s 多(从消息发送到MQ 到被消费的间隔): 2021-06-30T23:12: ...
- 【RocketMQ】消息的消费
上一讲[RocketMQ]消息的拉取 消息消费 当RocketMQ进行消息消费的时候,是通过ConsumeMessageConcurrentlyService的submitConsumeRequest ...
- 基于loghub的消息消费延迟监控
我们可以把loghub当作一个消息中间件来使用.如果能知道当前的消费进度,自然好了,否则消费情况一无所知,总是有点慌! loghub消费分两种情况,一是普通消费,二是消费组消费: 消费组消费,logh ...
- EQueue - 详细谈一下消息持久化以及消息堆积的设计
前言 之前写了一篇文章,总体介绍了EQueue.在看这篇文章之前如果还没看过那篇文章,可能会看不懂这篇文章.所以建议没看过的朋友务必先看一下那篇文章中所提到的各种概念,这样才能更好的理解本文所说的内容 ...
- rocketmq总结(消息的高可用、中间件选型)
rocketmq总结(消息的高可用.中间件选型) 参考: https://blog.csdn.net/meilong_whpu/article/details/76922456 http://blog ...
- RocketMQ之消费者启动与消费流程
vivo 互联网服务器团队 - Li Kui 一.简介 1.1 RocketMQ 简介 RocketMQ是由阿里巴巴开源的分布式消息中间件,支持顺序消息.定时消息.自定义过滤器.负载均衡.pull/p ...
随机推荐
- ABP-VNext 用户权限管理系统实战02---用户权限表的创建与迁移
一.表实体建立 1.菜单表 [Comment("菜单表")] [Table("t_identity_menu")] public class Menu : Au ...
- PKI系统
PKI系统简介 PKI(Public Key Infrastructure,公钥基础设施)是一种密码学框架,用于安全地管理数字证书.公钥和私钥,以确保通信和数据的机密性.完整性和身份验证.PKI建立在 ...
- 从零开始配置vim(27)——代码片段
我们之前介绍过缩写相关的内容,缩写是可以自动帮我们将缩写的单词展开成一段完整的话.但是代码本身是结构话的,仅仅使用缩写来配置是无法完成自动生成代码这个步骤的.好在我们大量的插件来进行配置.本篇我们将要 ...
- 数据挖掘机器学习[七]---2021研究生数学建模B题空气质量预报二次建模求解过程:基于Stacking机器学习混合模型的空气质量预测{含码源+pdf文章}
相关文章: 特征工程详解及实战项目[参考] 数据挖掘---汽车车交易价格预测[一](测评指标:EDA) 数据挖掘机器学习---汽车交易价格预测详细版本[二]{EDA-数据探索性分析} 数据挖掘机器学习 ...
- Python RE 正则表达式模块
正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex.regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为&qu ...
- 驱动开发:运用VAD隐藏R3内存思路
在进程的_EPROCESS中有一个_RTL_AVL_TREE类型的VadRoot成员,它是一个存放进程内存块的二叉树结构,如果我们找到了这个二叉树中我们想要隐藏的内存,直接将这个内存在二叉树中抹去,其 ...
- 爆了!Sealos 三天支持 1000 个帕鲁私服
Sealos 的帕鲁私服模板从第一天发布之后就起了 100 多个私服,第二天直接上到 500 多个,第三天直接上千,还在加速增长中.来讲讲我们只用一个晚上怎么做到上线一个专属可用区的,还有一些帕鲁实践 ...
- ProTab(高级表格)的使用
一. params 和 request 属性的使用 例子如下: import React, { useState } from 'react'; import { ProTable } from '@ ...
- Git企业开发控制理论和实操-从入门到深入(七)|企业级开发模型
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...
- Delphi 安装ICS
下载完成后解压到你的指写目录! 1.在library里加入ICS->Delphi->Vc32目录. 2.从File->Open中打开ICS->Delphi->Vc32-& ...