RocketMQ 客户端负载均衡机制详解及最佳实践

简介: 本文介绍 RocketMQ 负载均衡机制,主要涉及负载均衡发生的时机、客户端负载均衡对消费的影响(消息堆积/消费毛刺等)并且给出一些最佳实践的推荐。

作者:玄珏


前言


本文介绍 RocketMQ 负载均衡机制,主要涉及负载均衡发生的时机、客户端负载均衡对消费的影响(消息堆积/消费毛刺等)并且给出一些最佳实践的推荐。


负载均衡意义


1.png


上图是 RocketMQ 的消息储存模型:消息是按照队列的方式分区有序储存的。RocketMQ 的队列模型使得生产者、消费者和读写队列都是多对多的映射关系,彼此之间都可以无限水平扩展。对比传统的消息队列如 RabbitMQ 是很大的优势。尤其是在流式处理场景下有天然优势,能够保证同一队列的消息被相同的消费者处理,对于批量处理、聚合处理更友好。


2.png


消费者消费某个 topic 的消息等同于消费这个 topic 上所有队列的消息(上图中 Consumer A1 消费队列 1,Consumer A2 消费队列 2、3)。


所以,要保证每个消费者的负载尽量均衡,也就是要给这些消费者分配相同数量的队列,并保证在异常情况下(如客户端宕机)队列可以在不同消费者之间迁移。


负载均衡机制解析


负载均衡时机


负载均衡是客户端与服务端互相配合的过程,我们先综合服务端和客户端的职责回答第一个问题:何时会发生负载均衡。


  • 客户端主动负载均衡
     

3.png


上图是 RocketMQ 客户端相关类的结构,其中 MQClientInstance 负责和服务端的交互以及底层服务的协调,这其中就包括负载均衡。


MQClientInstance 中有两个相关的方法 rebalanceImmediately 和 doRebalance,我们分析负载均衡的时机只要找到何时调用这两个方法即可:


  1. 启动时立即进行负载均衡;
  2. 定时(默认 20s)负载均衡一次。

 

  • 服务端通知负载均衡
     

服务端通知客户端进行负载均衡也是通过 MQClientInstance#rebalanceImmediately 方法实现的,我们同样在服务端代码中寻找相关调用。


4.png


分析以上几个方法可以得出结论,在如下场景服务端会主动通知客户端触发负载均衡:


  1. 客户端上下线
  • 上线
  1. 新客户端发送心跳到服务端
  • 下线
  1. 客户端发送下线请求到服务端
  2. 底层连接异常:响应 netty channel 的 IDLE/CLOSE/EXCEPTION 事件

2. 订阅关系变化:订阅新 topic 或有旧的 topic 不再订阅


负载均衡策略


前文已经介绍了负载均衡实际是变更消费者负责处理的队列数量,这里每次需要变更的队列数量和受到影响的客户端数量是由负载均衡策略决定的。


我们来分析一下比较常见的负载均衡策略:


  • 平均分配


平均分配(AllocateMessageQueueAveragely)是默认的负载均衡策略:


如果我们有 4 个客户端,24 个队列,当第二个客户端下线时:


以默认的负载均衡策略(AllocateMessageQueueAveragely)为例,重新分配队列数量为 8。


默认的负载均衡策略能将队列尽量均衡的分配到每个客户端,但是每次负载均衡重新分配队列数量较多,尤其是在客户端数量很多的场景。


客户端 队列分配变化 队列数变化
Client1 1~6 -> 1~8 6 -> 8
Client2 7~12 -> - 6 -> 0
Client3 13~18 -> 9~16 6 -> 8
Client4 19~24 -> 17~24 6 -> 8
  • 一致性哈希


基于一致性哈希算法的负载均衡策略(AllocateMessageQueueConsistentHash)每次负载均衡会重新分配尽可能少的队列数量,但是可能会出现负载不均的情况。


客户端 队列分配变化 队列数变化
Client1 1~6 -> 1~9 6 -> 9
Client2 7~12 -> - 6 -> 0
Client3 13~18 -> 10~18 6 -> 9
Client4 19~24 -> 19~24 6 -> 8

负载均衡对消费的影响


我们以一个真实的线上场景来举例:


下图中绿色的线代表发送 tps,黄色的线代表消费 tps,我们很容易发现在 21:00 和 21:50 分左右存在消费毛刺。


5.png


这两个时间点在进行应用发布,根据我们上文的分析某个消费者下线后同组的其他消费者感知这一变化需要一定时间,导致有秒级的消费延迟产生。在发布结束后消费者快速处理堆积的消息,可以发现消费速度有一个明显的上涨。


这个例子展示了下线时由于负载均衡带来了短暂的消息处理延迟,新的消费者会从服务端获取消费位点继续之前的消费进度。如果消费者异常宕机或者没有调用 shutdown 优雅下线,没有上传自己的最新消费位点,会使得新分配的消费者重复消费。


这里我们总结下负载均衡对消费的影响,当某个客户端触发负载均衡时:


  1. 对于新分配的队列可能会重复消费,这也是官方要求消费要做好幂等的原因;
  2. 对于不再负责的队列会短时间消费停止,如果原本的消费 TPS 很高或者正好出现生产高峰就会造成消费毛刺。 


最佳实践


避免频繁上下线


为了避免负载均衡的影响应该尽量减少客户端的上下线,同时做好消费幂等。


同时在有应用重启或下线前要调用 shutdown 方法,这样服务端在收到客户端的下线请求后会通知客户端及时触发负载均衡,减少消费延迟。


选择合适的负载均衡策略


需要根据业务需要灵活选择负载均衡策略:


  • 需要保证客户端的负载尽可能的均衡:选择默认的平均分配策略;
  • 需要降低应用重启带来的消费延迟:选择一致性哈希的分配策略。 


当然还有其他负载均衡策略由于时间关系不一一介绍了,留给读者自行探索。


保证客户端订阅一致


RocketMQ 的负载均衡是每个客户端独立进行计算,所以务必要保证每个客户端的负载均衡算法和订阅语句一致。


  • 负载均衡策略不一致会导致多个客户端分配到相同队列或有客户端分不到队列;
  • 订阅语句不一致会导致有消息未能消费。 


RocketMQ 5.0 消息级别负载均衡


为了彻底解决客户端负载均衡导致的重复消费和消费延迟问题,RocketMQ 5.0 提出了消息级别的负载均衡机制。


同一个队列的消息可以由多个消费者消费,服务端会确保消息不重不漏的被客户端消费到:


6.png


消息粒度的负载均衡机制,是基于内部的单条消息确认语义实现的。消费者获取某条消息后,服务端会将该消息加锁,保证这条消息对其他消费者不可见,直到该消息消费成功或消费超时。因此,即使多个消费者同时消费同一队列的消息,服务端也可保证消息不会被多个消费者重复消费。


在 4.x 的客户端中,顺序消费的实现强依赖于队列的分配。RocketMQ 5.0 在消息维度的负载均衡的基础上也实现了顺序消费的语意:不同消费者处理同一个消息组内的消息时,会严格按照先后顺序锁定消息状态,确保同一消息组的消息串行消费。


7.png


如上图所述,队列 Queue1 中有 4 条顺序消息,这 4 条消息属于同一消息组 G1,存储顺序由 M1 到 M4。在消费过程中,前面的消息 M1、M2 被 消费者Consumer A1 处理时,只要消费状态没有提交,消费者 A2 是无法并行消费后续的 M3、M4 消息的,必须等前面的消息提交消费状态后才能消费后面的消息。


如果您对RocketMQ感兴趣,欢迎扫描下方二维码加入钉钉群一起沟通交流~


8.png


点击阅读原文,进入官网了解更多详情~

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
11天前
|
消息中间件 Java Spring
RocketMQ-JAVA客户端不同版本接入方式
RocketMQ4.0 RocketMQ5.0 JAVA接入 spring springboot
RocketMQ-JAVA客户端不同版本接入方式
|
6月前
|
消息中间件 弹性计算 Java
使用阿里云性能测试工具 JMeter 场景压测 RocketMQ 最佳实践
使用阿里云性能测试工具 JMeter 场景压测 RocketMQ 最佳实践
|
11天前
|
消息中间件 负载均衡 应用服务中间件
MQ产品使用合集之使用的RocketMQ5.1.3时,grpc客户端没有产生消息轨迹如何解决
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
44 3
|
11天前
|
负载均衡 算法 网络协议
原来还可以客户端负载均衡
原来还可以客户端负载均衡
44 0
|
11天前
|
Java Maven
【开源视频联动物联网平台】vertx写一个mqtt客户端
【开源视频联动物联网平台】vertx写一个mqtt客户端
56 1
|
11天前
|
消息中间件 关系型数据库 MySQL
使用Nginx的stream模块实现MySQL反向代理与RabbitMQ负载均衡
使用Nginx的stream模块实现MySQL反向代理与RabbitMQ负载均衡
104 0
|
11天前
|
缓存 负载均衡 应用服务中间件
【分布式技术专题】「分析Web服务器架构」Tomcat服务器的运行架构和LVS负载均衡的运行机制(修订版)
在本章内容中,我们将深入探讨 Tomcat 服务器的运行架构、LVS 负载均衡的运行机制以及 Cache 缓存机制,并提供相应的解决方案和指导。通过理解这些关键概念和机制,您将能够优化您的系统架构,提高性能和可扩展性。
214 4
【分布式技术专题】「分析Web服务器架构」Tomcat服务器的运行架构和LVS负载均衡的运行机制(修订版)
|
11天前
|
消息中间件 负载均衡 算法
RocketMQ源码(三)简单探索Producer和Consumer与Queue之间的负载均衡策略
- Producer如何将消息负载均衡发送给queue? - Consumer如何通过负载均衡并发消费queue的消息?
477 0
|
11天前
|
消息中间件 运维 负载均衡
负载均衡中后端连了三个rabbitmq,如果挂了一个,客户端连接mq会变慢吗
在负载均衡中使用三个 RabbitMQ 实例,如果其中一个实例发生故障,可能会影响客户端连接到 RabbitMQ 的性能。具体影响取决于负载均衡的配置和客户端的实现方式。 如果负载均衡器能够及时检测到故障的 RabbitMQ 实例并将流量路由到正常的实例,那么客户端连接的性能影响可能较小。但如果负载均衡器不能迅速切换流量或者客户端实现不支持及时的连接故障转移,那么可能会导致客户端连接的延迟或失败。 在设计这样的架构时,有一些考虑因素: 1. **健康检查和故障切换:** 确保负载均衡器能够定期检查 RabbitMQ 实例的健康状态,并在出现故障时快速将流量切换到其他正常的实例。 2.
|
11天前
|
负载均衡 算法 Nacos
【Ribbon实现客户端负载均衡和故障转移】—— 每天一点小知识
【Ribbon实现客户端负载均衡和故障转移】—— 每天一点小知识
168 0

热门文章

最新文章

相关产品

  • 云消息队列 MQ