# 概述
# 系统部署架构
图中所涉及到的概念如下所述:
- Name Server:是一个几乎无状态节点,可集群部署,在消息队列 RocketMQ 版中提供命名服务,更新和发现 Broker 服务。
- Broker:消息中转角色,负责存储消息,转发消息。分为 Master Broker 和 Slave Broker,一个 Master Broker 可以对应多个 Slave Broker,但是一个 Slave Broker 只能对应一个 Master Broker。Broker 启动后需要完成一次将自己注册至 Name Server 的操作;随后每隔 30s 定期向 Name Server 上报 Topic 路由信息。
- 生产者:与 Name Server 集群中的其中一个节点(随机)建立长链接(Keep-alive),定期从 Name Server 读取 Topic 路由信息,并向提供 Topic 服务的 Master Broker 建立长链接,且定时向 Master Broker 发送心跳。
- 消费者:与 Name Server 集群中的其中一个节点(随机)建立长连接,定期从 Name Server 拉取 Topic 路由信息,并向提供 Topic 服务的 Master Broker、Slave Broker 建立长连接,且定时向 Master Broker、Slave Broker 发送心跳。Consumer 既可以从 Master Broker 订阅消息,也可以从 Slave Broker 订阅消息,订阅规则由 Broker 配置决定。
# RocketMQ 的设计理念和目标
# 设计理念
RocketMQ 设计基于主题的发布订阅模式,其核心功能包括消息发送、消息存储(Broker)、消息消费,整体设计追求简单和性能第一,主要体现在如下三个方面。
首先,NameServer
设计极其简单,摒弃了Zookeeper
充当注册中心,采用自研NameServer
实现元数据的管理(Topic路由信息等),追求最终一致性,并且能容忍分钟级的不一致。
正式基于此种情况,RocketMQ的NameServer
集群间互不通信,极大地降低了NameServer
实现的复杂程度,对网络的要求也降低不少,性能相对于Zookeeper
有较大提升。
其次,是高效的IO存储机制。RocketMQ 追求消息发送的高吞吐量,消息存储文件设计成文件组的概念,组内单个文件大小固定,方便引入内存映射机制,所有主题的消息存储基于顺序写, 极大地提升了消息写性能,同时为了兼顾消息消费与消息查找,引入了消息消费队列文件与索引文件
最后,容忍存在设计缺陷,RocketMQ 只保证消息被消费者消费,但设计上允许消息被重复消费,这样极大地简化了消息中间件的内核,使得实现消息发送高可用变得非常简单与高效, 消息重复问题由消费者在消息消费时实现幂等。
# 设计目标
RocketMQ 需要解决一下问题:
# 1.架构模式
RocketMQ 采用发布订阅模式,基本组件:消息发送者,消息服务器(消息存储),消息消费,路由发现。
# 2.顺序消息
顺序消息,指消息消费者按照消息到达消息存储服务器的顺序消费,RocketMQ 可以严格保证消息有序。
# 3.消息过滤
消息过滤,指消息消费时,消息消费者可以对同一主题下的消息按照规则只消费自己感兴趣的消息。RocketMQ 消息过滤支持在服务端和消费端的消息过滤机制。
- 消息在
Broker
端过滤。Broker
只将消息消费者感兴趣的消息发送消息消费者。 - 消息在消息消费端过滤。过滤方式由消费者自定义,缺点是无用的消息会从
Broker
传输到消费端。
# 4.消息存储
核心实现是消息存储,两个维度考量:消息堆积能力和消息存储性能。**引入内存映射机制和顺序写提升消息存储性能,**为了避免消息无限在消息存储服务器中累积,引入消息文件过期机制和文件存储空间报警机制。
# 5.消息高可用性
消息可靠性通常有以下几种情况:
- Broker 正常关机
- Broker异常 Crash
- OS Crash
- 机器断电,但是能立即恢复供电
- 机器无法开机
- 磁盘设备损坏
情况 1~4 的 RocketMQ 在同步刷盘模式下可以确保不丢失消息,在异步刷盘模式下,会丢失少量消息。情况 5~6 属于单点故障,一旦发生,该节点消息全部丢失,若开启异步复制,RocketMQ 能保证只丢失少量消息。
# 6.消息到达(消费)低延迟
RocketMQ在消息不发生堆积时,以长轮询模式实现准实时的消息推送模式
# 7.确保消息必须被消费一次
RocketMQ 通过消息确认机制(ACK)来确保消息至少被消费一次(由于ACK消息有可能丢失等原因,无法做到只被消费一次,有重复消费的可能)。
# 8.回溯消息
回溯消息,指已经消费成功但需要重新消费的消息。RocketMQ 支持按时间回溯消息,时间维度可精确到毫秒,可向前或向后回溯
# 9.消息堆积
消息中间件的主要功能是异步解耦,必须具备应对前端的数据洪峰,提高后端系统的可用性,必然要求消息中间件具备一定的消息堆积能力。 RocketMQ 消息存储使用磁盘文件(内存映射机制),在物理布局上为多个大小相等的文件组成逻辑文件组,可以无限循环使用。RocketMQ消息存储提供过期机制,默认保留3天。
# 10.定时消息
定时消息,指消息发送到Broker后,不能被消费端立即消费,要到特定的时间点或等待特定的时间后才能被消费。RocketMQ只支持特定延迟级别。若支持任意精度的定时消费,必须在消息服务端对消息进行排序,性能损耗很大。
# 11.消息重试机制
消息重试,指消息在消费时,如果发送异常,消息中间件支持消息重新投递,RocketMQ支持消息重试机制.
# RocketMQ 的存储机制 🎉
- CommitLog
- 消息主体以及元数据的存储主体
- 单个文件大小默认1G ,文件名长度为20位,左边补零,剩余为起始偏移量
- 消息主要是顺序写入日志文件,当文件满了,写入下一个文件。
- ConsumeQueue
- 消息消费队列,引入的目的主要是提高消息消费的性能
- ConsumeQueue(逻辑消费队列)作为消费消息的索引,保存了指定 Topic 下的队列消息在 CommitLog 中的起始物理偏移量 offset ,消息大小 size 和消息 Tag 的 HashCode 值
- ConsumeQueue 文件可以看成是基于 topic 的 CommitLog 索引文件
- IndexFile(索引文件)提供了一种可以通过
key
或时间区间来查询消息的方法
# RocketMQ 消费者的负载均衡策略 🎉
消费者的负载均衡,简单来说就是将Topic下的MessageQueue分配给这些Consumer
- 平均分配
- 环形平均分配
# Kafka 与 RocketMQ 的存储对比 🎉
MQ | 结构 | 存储 |
---|---|---|
Kafka | topic 对应多个 partition,同一个服务器(Broker)会有多个 topic-partition 对,partition 为单主多从结构,主挂了会重新选择主(ZK) | 消息直接存储在 partition 中,对单 topic 为顺序写 |
RocketMQ | topic 对应多个 ConsumeQueue,同一个服务器(Broker)会有多个 topic-ConsumeQueue 对,ConsumeQueue 为多主多从结构,主有配置指定,主挂了由其他主提供服务 | 同一个服务器的所有消息都统一写到 CommitLog 文件中,ConsumeQueue 只存储在 CommitLog 中的起始offset、log大小、MessageTag的hashCode,数据量较少。 |
# RocketMQ 内存映射机制 🎉
RocketMQ 通过使用内存映射文件(内存映射机制)来提高IO访问性能
,无论是 CommitLog、 ConsumeQueue 还是 IndexFile,单个文件都被设计为固定长度,如果一个文件写满以后再创建一个新文件,文件名就为该文件第一条消息对应的全局物理偏移量。
参考文档