目录

RocketMQ(一) 架构

技术架构

/img/2021/02/rocketmq_architecture_1.png
RocketMQ技术架构

Producer

消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。

Consumer

消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求。

NameServer

NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。

主要包括两个功能:

  1. Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;
  2. 路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费。

NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。

Broker向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer, Consumer 仍然可以动态感知Broker的路由的信息。

这样的设计有很多好处:
  1. 这样可以使Name Server之间可以没有任何关联,因为注册到它们的Broker是一样的。
  2. 作为Producer或者Consumer可以绑定任何一个Name Server 因为它们都是一样的。

BrokerServer

RocketMQ BrokerServer

BrokerServer 主要负责消息的存储、投递和查询以及服务高可用保证,为了实现这些功能,BrokerServer 包含了以下几个重要子模块。

  1. Remoting Module:整个Broker的实体,负责处理来自clients端的请求。
  2. Client Manager:负责管理客户端(Producer/Consumer)和维护Consumer的Topic订阅信息。
  3. Store Service:提供方便简单的API接口处理消息存储到物理硬盘和查询功能。
  4. HA Service:高可用服务,提供Master Broker 和 Slave Broker之间的数据同步功能。
  5. Index Service:根据特定的Message key对投递到Broker的消息进行索引服务,以提供消息的快速查询。

部署架构

RocketMQ 部署架构

NameServer

NameServer是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。

BrokerServer

Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master。

Master与Slave 的对应关系通过指定相同的BrokerName,不同的BrokerId 来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。

每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。

注意:当前RocketMQ版本在部署架构上支持一Master多Slave,但只有BrokerId=1的从服务器才会参与消息的读负载。

Producer

Producer 与 NameServer 集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Master 建立长连接,且定时向 Master 发送心跳。

Producer 完全无状态,可集群部署。

Consumer

Consumer 与 NameServer 集群中的其中一个节点(随机选择)建立长连接,定期从 NameServer 获取 Topic 路由信息,并向提供 Topic 服务的 Master 、Slave 建立长连接,且定时向Master、Slave发送心跳。

Consumer 既可以从 Master 订阅消息,也可以从 Slave 订阅消息,消费者在向 Master 拉取消息时,Master 服务器会根据拉取偏移量与最大偏移量的距离(判断是否读老消息,产生读I/O),以及从服务器是否可读等因素建议下一次是从 Master 还是 Slave 拉取。

集群工作流程

/img/2021/02/rocketmq_architecture_3.png
RocketMQ 集群工作流程

启动NameServer

启动NameServer,NameServer起来后监听端口,等待Broker、Producer、Consumer连上来,相当于一个路由控制中心。

启动Broker

启动Broker,跟所有的NameServer保持长连接,定时发送心跳包。心跳包中包含当前Broker信息(IP+端口等)以及存储所有Topic信息。注册成功后,NameServer集群中就有Topic跟Broker的映射关系。

Broker 与 Name Server 关系

  • 连接: 单个Broker和所有Name Server保持长连接。
  • 心跳间隔: 每隔30秒向所有NameServer发送心跳,心跳包含了自身的Topic配置信息。
  • 心跳超时: NameServer每隔10秒,扫描所有还存活的Broker连接,若某个连接2分钟内没有发送心跳数据,则断开连接。

Broker 的负载均衡

一个Topic分布在多个Broker上,一个Broker可以配置多个Topic,它们是多对多的关系。

如果某个Topic消息量很大,应该给它多配置几个Queue,并且尽量多分布在不同Broker上,减轻某个Broker的压力。

Broker 的可靠性

由于消息分布在各个Broker上,一旦某个Broker宕机,则该Broker上的消息读写都会受到影响。

RocketMQ支持消息的高可靠,影响消息可靠性的几种情况:

  1. Broker非正常关闭
  2. Broker异常Crash
  3. OS Crash
  4. 机器掉电,但是能立即恢复供电情况
  5. 机器无法开机(可能是cpu、主板、内存等关键设备损坏)
  6. 磁盘设备损坏

1)、2)、3)、4) 四种情况都属于硬件资源可立即恢复情况,RocketMQ在这四种情况下能保证消息不丢,或者丢失少量数据(依赖刷盘方式是同步还是异步)。

5)、6) 属于单点故障,且无法恢复,一旦发生,在此单点上的消息全部丢失。RocketMQ在这两种情况下,通过异步复制,可保证99%的消息不丢,但是仍然会有极少量的消息可能丢失。通过同步双写技术可以完全避免单点,同步双写势必会影响性能,适合对消息可靠性要求极高的场合,例如与Money相关的应用。 注:RocketMQ从3.0版本开始支持同步双写。

思考1、一旦某个 broker master 宕机,生产者和消费者多久才能发现?

受限于 RocketMQ 的网络连接机制,默认情况下最多需要30秒,因为消费者每隔30秒从 NameServer 获取所有 Topic 的最新队列情况,这意味着某个 Broker 如果宕机,客户端最多要30秒才能感知。

思考2、Master 恢复恢复后,消息能否恢复。

消费者得到 Master 宕机通知后,转向 Slave 消费,但在非同步双写下 Slave 不能保证 Master 的消息 100% 都同步过来了,因此会有少量的消息丢失。当 Master 恢复,未同步到 Slave 的消息会被消费掉。

创建Topic

Topic是一个逻辑上的概念,实际上Message是在每个Broker上以Queue的形式记录。

/img/2021/02/rocket-topic.jpg
RocketMQ Topic

收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic (不推荐)。

从上面的图片可以总结下几条结论:
  1. 消息会在Broker中的Queue队列中记录。
  2. 一个Topic的数据可能会存在多个Broker中。
  3. 一个Broker存在多个Queue。
  4. 单个的Queue也可能存储多个Topic的消息。

每个Topic在Broker上会划分成几个逻辑队列,每个逻辑队列保存一部分消息数据,但是保存的消息数据实际上不是真正的消息数据,而是指向commit log的消息索引。更多细节请见 《RocketMQ(二) 设计》

RocketMQ 集群工作流程

Producer发送消息

Producer 发送消息,启动时先跟 NameServer 集群中的其中一台建立长连接,并从 NameServer 中获取当前发送的 Topic 存在哪些 Broker 上,轮询从队列列表中选择一个队列,然后与队列所在的 Broker 建立长连接从而向 Broker 发消息。

Producer 与 Name Server 关系

  • 连接: 单个 Producer 和一台 NameServer 保持长连接,如果该 NameServer 挂掉,生产者会自动连接下一个 NameServer,直到有可用连接为止,并能自动重连。
  • 心跳: 与 NameServer 没有心跳。
  • 轮询时间: 默认情况下,生产者每隔30秒从 NameServer 获取所有 Topic 的最新队列情况,这意味着某个 Broker 如果宕机,生产者最多要30秒才能感知,在此期间, 发往该 Broker 的消息发送失败。

Producer 与 Broker 关系

  • 连接: 单个生产者和该生产者关联的所有 Broker 保持长连接。

Consumer订阅消息

Consumer 跟 Producer 类似,跟其中一台 NameServer 建立长连接,获取当前订阅 Topic 存在哪些 Broker 上,然后直接跟 Broker 建立连接通道,开始消费消息。

Consumer 与 Name Server 关系

  • 连接: 单个 Consumer 和一台 NameServer 保持长连接,如果该 NameServer 挂掉,消费者会自动连接下一个 NameServer,直到有可用连接为止,并能自动重连。
  • 心跳: 与 NameServer 没有心跳
  • 轮询时间: 默认情况下,消费者每隔30秒从 NameServer 获取所有 Topic 的最新队列情况,这意味着某个 Broker 如果宕机,客户端最多要30秒才能感知。

Consumer 与 Broker 关系

  • 连接: 单个消费者和该消费者关联的所有 Broker 保持长连接。

Consumer 的负载均衡

  • 集群消费模式下,一个消费组集群的多台机器共同消费一个 Topic 的多个队列,一个队列只会被一个消费者消费。如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。