RocketMQ总结

一、路由管理

  NameServer是RocketMQ的路由中心,负责为Producer和Consumer提供Topic路由信息。NameServer集群各节点是无状态的(相互没有联系),每个节点的路由信息依靠与Broker的心跳来更新,实现路由信息的最终一致性,如下图所示:
在这里插入图片描述

路由注册

  Broker启动后会定时向NameServer集群各节点发送心跳包,NameServer节点收到心跳包后会更新路由信息,以及Broker的心跳时间戳等信息;

路由删除

  NameServer节点会定时扫描缓存中各Broker的心跳时间信息,如果发现超过120s没有收到心跳,则该Broker的路由信息会被移除,同时关闭对应的Sokcet连接;

路由发现

  RocketMQ的路由发现是非实时的,当Topic的路由信息发生变更时,NameServer并不会主动推送给Producer和Consumer,而是由Producer和Consumer定时拉取路由信息来更新;(Producer会有容错机制来保障消息发送的高可用性)

二、消息发送

消息发送方式

  RocketMQ支持3种消息发送方式:同步(sync)、异步(async)和单向(oneway)。

  • 同步:发送消息时,同步等待发送结果;
  • 异步:发送消息时,注册回调函数,无需等待发送结果;
  • 单向:只管发送,不关心发送结果;
消息队列负载均衡

  RocketMQ默认采用RR策略进行负载均衡,大致过程如下:

  1. 首先,对消息队列进行排序,优先按照BrokerName排序,BrokerName相同时按照消息队列的序号排序;
  2. 其次,计数器对消息队列取模,每发送一条消息计数器加1;

问题: RR策略存在消息发送高可用的问题,当某个Broker宕机后,向Broker上面所有的队列发送的消息都会失败;

消息发送高可用

  RocketMQ实现消息发送高可用的策略为 : 重试与 Broker 故障规避 。 Broker故障规避是指在一次消息发送过程中如果向某个Broker的消息发送失败,则在某一时间段内,Producer不会再向Broker上的消息队列发送消息,提高发送消息的成功率 。

三、消息存储架构

主要存储文件
  • CommitLog: 消息存储文件,当Broker接收到消息后(所有Topic的)会顺序写入CommitLog文件(Kafka每个Topic都有独立的数据文件,当Topic数量变多消息持久化逐渐变成一种随机写磁盘的行为)。每个CommitLog文件大小固定为1G,以第一条记录的偏移量作为文件名。(顺序写、随机读
  • ConsumeQueue: 消息队列文件,相当于消息的索引,提升消息消费性能。每个Topic有多个队列/分区,每个分区对应一个ConsumeQueue文件。消息队列文件固定包含30万个记录,每条记录固定大小为20字节,单个文件大小约5.72M,适合加载到内存。(顺序写、顺序读
  • IndexFile: 索引文件,相当于HashMap,用于根据消息的key快速查找消息的场景。单个IndexFile文件有50万个哈希槽位,2000万个哈希记录;
    在这里插入图片描述
刷盘策略
  • 同步刷盘:消息追加到内存映射文件的内存后,立即将数据从内存刷写到磁盘,然后返回ACK;
  • 异步刷盘:消息追加到内存映射文件的内存后,立即返回ACK,然后由后台异步线程将数据从内存刷写到磁盘;
文件恢复机制

问题: 由于索引信息是异步的,如果Broker异常宕机,可能导致数据文件与索引文件数据不一致,如下图所示:
在这里插入图片描述
解决方案:

  1. 首先,判断Broker是否异常退出;
      Broker启动时会生成abort文件,正常退出时会通过JVM钩子函数销毁abort文件,因此可以在Broker启动时判断abort文件是否存在来判断Broker是否异常退出;
  2. 然后,根据Broker是否异常退出采取不同的方案;
      如果是正常退出,说明消息数据都已经刷入磁盘,索引数据也都被更新,数据文件与索引文件是一致的;否则,PageCache中还没刷入磁盘的数据会丢失,数据文件与索引文件也可能不一致,核心思路是取三个文件中刷盘偏移量最小的FlushedPosition,然后CommitLog文件从自此处开始重新构建索引信息;

四、消息消费

负载均衡(消费端)

负载均衡算法: RocketMQ提供了5中负载均衡算法,最常用的是平均分配法。举例来说,如果现在有6 个消息消费队列和2个消费者,消息队列分配如下图所示。消息队列的分配遵循一个原则:一个消息队列只能分配给一个消费者,一个消费者可以分配多个队列,当消费者数量大于消息队列数量时,会有消费者空闲下来。
在这里插入图片描述
负载均衡过程:

  1. 每个消费者有个负载均衡的线程,定时从NameServer获取路由信息;
  2. 对队列和消费者进行排序;
  3. 按照设定的负载均衡算法生成新的集合;
  4. 对比新老集合,停止消费不在新集合中的队列,同时保存消费进度,开始消费新分配的队列;
延迟消息

  处于性能考虑,RocketMQ只支持特定级别的延迟消息,延迟消息的Topic名称为SCHEDULE TOPIC XXXX,每个延迟级别对应一个消息队列,如下图所示。核心思想是先将消息加入延迟队列,当时间到达后再写入消息队列进行计时,像普通消息一样消息,具体过程如下:

  1. 当Broker接收到延迟消息后,首先更改消息Topic名称为SCHEDULE TOPIC XXXX,写入CommitLog文件;
  2. 然后根据延迟级别追加索引信息到对应的消息队列;
  3. 每个消息队列有定时任务,当消息到达时间后将消息名称还原,重新写入CommitLog文件,并更新对应的消息队列;
  4. 消费者拉取消息并消费;

在这里插入图片描述

普通消息/并发消费

  并发消费也称为乱序消费,相比于顺序消费,并发消费没有加锁/解锁的过程,所以消费速度要快很多,因此是RocketMQ默认的消费方式,具体过程如下:

  1. 消费端的PullMessageService线程不断从Broker拉取消息(无锁);
  2. 拉取到的消息存储到ProcessQueue,并创建消费任务(包含消息,不用从ProcessQueue拉取)提交到线程池;
  3. 消费线程消费完消息后,删除ProcessQueue中对应的消息,并以最小偏移量更新消费进度;
    在这里插入图片描述
顺序消息

  RocketMQ的顺序消息分为2种情况:局部有序和全局有序。

  • 局部有序:单个队列内的消息保持有序性,相同Topic的不同队列间是无序的;(实际常用,将需要保持顺序性消息发送到相同队列)
  • 全局有序:相同Topic的不同队列间消息保持有序性(通过将队列树设为1实现);

顺序发送原理: 将需要保持顺序的消息同步发送到相同队列即可,如下图所示。
顺序消费原理:

  1. 消费端从Broker队列拉取消息时,需要先加锁,只有加锁成功才能拉取消息;(防止负载均衡时被其它队列消费)
  2. 拉取到的消息存储到本地ProcessQueue,按照偏移量从小到大排序,创建消费任务(不包含消息,需从ProcessQueue拉取)提交到线程池;
  3. 消费线程获取ProcessQueue的锁,消费偏移量最小的消息,然后释放锁;
  4. 消费成功后更新消费进度到Broker;

将需要保持顺序的消息同步发送到相同队列即可,如下图所示。
在这里插入图片描述
说明: 当发生分区变更(扩容、缩容)、Broker宕机、或者主从切换时都会导致发送端将消息路由到其它分区,导致消息短暂的乱序。如果想要保持”严格有序“,则Topic单个分区,同时容忍短暂的不可用(故障恢复)。

事务消息

  事务消息的核心原理:两阶段提交 + 超时回调。类似于延迟消息,发送方在阶段一发送Prepare消息后,会更改消息Topic为RMQ_SYS_TRANS_HALF_TOPIC(暂时对消费方不可见)。如果发送方在阶段二Commit,则恢复消息重新存入Commit以及对应的消息队列(对消费者可见);如果Rollback,则删除对应的Prepare消息。RMQ_SYS_TRANS_HALF_TOPIC的消息队列会有定时任务,如果Prepare消息超时没有提交或回滚,则回调发送方进行确认,具体过程如下图所示:
在这里插入图片描述

在这里插入图片描述

五、架构设计

5.1 高性能
  1. 对于整个集群,支持水平扩展,可通过增加节点提升集群的存储量和吞吐量;
  2. 对于Broker,通过磁盘顺序写、索引文件加速读、PageCache读写、异步刷盘、mmap零拷贝,以及文件预热等方式提升单节点性能;文件预热:提前进行commitlog文件的创建和加载,避免消息写入时导致的延迟;
  3. 对于Producer和Consumer,通过将topic对应的消息队列分散到多个Broker上,支持多个并发的发送和消费消息;
  4. 底层通信模型基于Netty,IO模型使用NIO;
5.2 高可用

  Broker的主备结构实现,Master支持读写,Slave支持读。当主节点挂掉后,对于Consumer,从主切换到从继续读取;对于Producer,通过故障规避机制发送到其他Broker上;
  主从同步:主从之间建立连接,从服务器上报未拉取消息偏移量,主服务器推送消息到从服务器;可以分为同步和异步两种;

参考:

  1. 深度解析RocketMQ Topic的创建机制
  2. RocketMQ——水平扩展及负载均衡详解
  3. 事务消息官方文档
  4. RocketMQ - 如何实现顺序消息
  5. 深度剖析 Kafka/RocketMQ 顺序消息的一些坑
  6. 《RocketMQ技术内幕》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值