RocketMQ(一) 架构
技术架构
Producer
消息发布的角色,支持分布式集群方式部署。Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。
Consumer
消息消费的角色,支持分布式集群方式部署。支持以push推,pull拉两种模式对消息进行消费。同时也支持集群方式和广播方式的消费,它提供实时消息订阅机制,可以满足大多数用户的需求。
NameServer
NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。
主要包括两个功能:
- Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;
- 路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费。
NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。
Broker向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer, Consumer 仍然可以动态感知Broker的路由的信息。
- 这样可以使Name Server之间可以没有任何关联,因为注册到它们的Broker是一样的。
- 作为Producer或者Consumer可以绑定任何一个Name Server 因为它们都是一样的。
BrokerServer
BrokerServer 主要负责消息的存储、投递和查询以及服务高可用保证,为了实现这些功能,BrokerServer 包含了以下几个重要子模块。
- Remoting Module:整个Broker的实体,负责处理来自clients端的请求。
- Client Manager:负责管理客户端(Producer/Consumer)和维护Consumer的Topic订阅信息。
- Store Service:提供方便简单的API接口处理消息存储到物理硬盘和查询功能。
- HA Service:高可用服务,提供Master Broker 和 Slave Broker之间的数据同步功能。
- Index Service:根据特定的Message key对投递到Broker的消息进行索引服务,以提供消息的快速查询。
部署架构
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 拉取。
集群工作流程
启动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上的消息读写都会受到影响。
RocketMQ支持消息的高可靠,影响消息可靠性的几种情况:
- Broker非正常关闭
- Broker异常Crash
- OS Crash
- 机器掉电,但是能立即恢复供电情况
- 机器无法开机(可能是cpu、主板、内存等关键设备损坏)
- 磁盘设备损坏
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的形式记录。
收发消息前,先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,也可以在发送消息时自动创建Topic (不推荐)。
- 消息会在Broker中的Queue队列中记录。
- 一个Topic的数据可能会存在多个Broker中。
- 一个Broker存在多个Queue。
- 单个的Queue也可能存储多个Topic的消息。
每个Topic在Broker上会划分成几个逻辑队列,每个逻辑队列保存一部分消息数据,但是保存的消息数据实际上不是真正的消息数据,而是指向commit log的消息索引。更多细节请见 《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 的多个队列,一个队列只会被一个消费者消费。如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。