一、MQ 与 RocketMQ 核心概念
1. MQ(消息队列)简介
定义:MQ(MessageQueue,消息队列)是互联网中广泛使用的服务中间件,核心能力是消息跨进程传输与队列数据缓存。消息是不同进程间传递的数据,队列是具有 FIFO(先进先出)特性的数据结构。
MQ 的三大核心作用:
- 异步:提高系统响应速度和吞吐量。例如快递员将包裹放入菜鸟驿站后即可继续派送,无需等待客户当面签收。
- 解耦:减少服务间相互影响,提升系统稳定性和可扩展性;同时支持数据分发,一个生产者消息可被多个消费者消费,消费者增减不影响生产者。
- 削峰:以稳定系统资源应对突发流量冲击。例如三峡大坝蓄水,下游缓慢排水,避免洪峰直接冲击。
2. RocketMQ 产品介绍与特点
背景:RocketMQ 是阿里巴巴开源的消息中间件,历经双十一等超大规模高并发场景考验,可处理亿万级消息,2016 年捐赠给 Apache,现为 Apache 顶级项目。早期阿里使用 ActiveMQ 遇 IO 瓶颈,转向 Kafka 后发现其针对日志场景设计,Topic 过多时 Partition 文件过多导致 IO 性能下降,因此自研 MetaQ(后更名 RocketMQ),核心目标是解决多 Topic 下的 IO 性能压力。
主流 MQ 产品横向对比:
| 产品 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| Apache Kafka | 吞吐量极大,性能好,集群高可用 | 可能丢数据,功能较单一 | 日志分析、大数据采集 |
| RabbitMQ | 消息可靠性高,功能全面 | Erlang 语言不好定制,吞吐量较低 | 企业内部小规模服务调用 |
| Apache Pulsar | 基于 BookKeeper,消息可靠性非常高 | 周边生态有差距,使用公司较少 | 企业内部大规模服务调用 |
| Apache RocketMQ | 高吞吐、高性能、高可用,功能全面,Java 开发易定制 | 服务加载较慢 | 几乎全场景,特别适合金融场景 |
RocketMQ 核心优势:吞吐量略低于 Kafka 但远高于 RabbitMQ;消息可靠性优于 Kafka;具备广播消费、延迟队列、死信队列、事务消息等全面高级功能,尤其适合金融互联网场景。阿里内部每天处理请求超 5 万亿次,支撑核心应用超 3000 个。
二、RocketMQ 快速实战要点
1. 快速搭建 RocketMQ 服务
- 版本选择:采用 5.3.0 版本。5.0 是里程碑大版本,重构代码量超 60%;4.x 系列已于 2024 年 3 月停止维护,不建议使用。重要目录介绍如图:
- 环境要求:需安装 JDK(示例用 1.8);生产环境建议至少 12G 内存,学习环境可修改
runserver.sh和runbroker.sh降低 JVM 内存。 - 启动 NameServer:
nohup bin/mqnamesrv &,日志出现The Name Server boot success即成功,默认端口 9876。 - 启动 Broker:先配置环境变量
export NAMESRV_ADDR='localhost:9876',再执行nohup bin/mqbroker &,日志出现The broker boot success即成功。云服务器多网卡时需配置brokerIP1指向外网 IP。 - 常用指令:
mqshutdown namesrv关闭 NameServer;mqshutdown broker关闭 Broker;jps查看进程。
2. 快速实现消息收发
- 命令行方式
cd /app/rocketmq/rocketmq-all-5.3.0-bin-release #命令行发送消息 bin/tools.sh org.apache.rocketmq.example.quickstart.Producer #命令行消费消息 bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer - Java 客户端:Maven 引入
rocketmq-client依赖;生产者用DefaultMQProducer,指定 NameServer 地址后start()发送消息;消费者用DefaultMQPushConsumer,指定 NameServer、订阅 Topic、注册消息监听器后start()。 - 关键点:生产者和消费者都必须指定 NameServer 地址;消费者必须订阅与消息一致的 Topic。
3. 可视化管理服务 Dashboard
Dashboard 需单独从官网下载源码,用 Maven 编译生成 jar 包,命令:mvn clean package -Dmaven.test.skip=true,配置application.yml指定 NameServer 地址后java -jar启动,通过 Web 页面管理集群、Topic、消费进度等。
application.yml配置信息如下:
rocketmq:
config:
namesrvAddrs:
- 192.168.65.112:9876
4. 升级分布式集群(主从架构)
- 目的:防止单点故障导致消息丢失。
- 架构:基于主从架构,Master 响应客户端请求,Slave 备份数据。
- 核心配置项:
brokerClusterName(集群名,相同则自动组集群)、brokerName(Broker服务名,相同则为一组主从)、brokerId(RocketMQ中对每个服务的唯一标识。0 为 Master,大于 0 为 Slave)、brokerRole(服务的角色。ASYNC_MASTER/SYNC_MASTER/SLAVE)、namesrvAddr(默认占用9876端口,多个地址用分号分隔)。 - 管理指令:
bin/mqadmin clusterList查看集群状态。
5. 升级 Dledger 高可用集群
- 背景:主从架构中 Slave 无法自动升级为 Master,broker 宕机后该节点消息需等待重启才能消费,不具备服务高可用。
- Dledger 机制:基于 Raft 协议自动选举 Leader(类似 Master)响应请求,Follower 备份数据并随时准备升级。只要超过半数节点正常工作,集群即可正常工作,因此通常部署奇数台。
- 核心配置:
enableDLegerCommitLog=true、dLegerGroup(Raft Group 名)、dLegerPeers(各节点地址端口,同组必须一致)、dLegerSelfId(节点唯一 ID)、sendMessageThreadPoolNums(建议 CPU 核心数)。 - Raft 协议解决脑裂问题:通过选举机制(需多数节点同意)、任期编号、心跳机制、日志复制,确保集群只有一个 Leader,避免网络分区导致多个 Master 的脑裂问题。
- 注意:Dledger 接管文件写入,写入速度比原生慢,当前企业使用不多;5.0 提供 Dledger Controller 模式,仅用选举功能,提升性能。
RocketMQ是一款分布式消息队列系统,主要用于处理大量数据的实时传输和处理。在RocketMQ中,DLedger是一个为高可用、高性能、高可靠的分布式存储系统提供基础支持的组件。DLedger集群主要具有以下功能:
数据复制:DLedger集群通过raft协议来保证数据的一致性。在集群中,每个节点都维护一个相同的数据副本,以确保当某个节点出现故障时,数据不会丢失。
容错性:DLedger集群具有很高的容错性。即使集群中的部分节点发生故障,只要集群中有大多数节点(即超过半数)仍在正常工作,整个集群将继续提供服务。
高可用性:DLedger集群通过负载均衡和热备份等机制,确保在节点故障时能够快速切换到其他正常节点,提高整个系统的可用性。
分布式锁:DLedger集群提供分布式锁功能,可以解决分布式系统中的资源争用问题,实现跨节点的资源同步。
强一致性:DLedger集群通过使用Raft一致性协议,确保在多个副本节点之间同步数据,保证数据的强一致性。
高性能:DLedger集群支持水平扩展,可以通过增加节点来提高系统的吞吐量和存储能力,以满足不断增长的业务需求。
易于管理:DLedger集群提供了一系列管理和监控功能,使运维人员可以更方便地掌握系统的运行状况,及时发现和解决问题。
DLedger集群其背后的核心就是Raft协议。这是一种强大的分布式选举算法,其核心是只要集群中超过半数的节点作出的共同决议,就认为是集群最终的共同决议。Raft协议通过投票机制保持数据一致性。
三、RocketMQ 运行架构与消息模型
1. 运行架构三大组件
- NameServer(命名服务):独立启动,不依赖其他服务;Broker 和客户端都必须指定其地址。类比电脑 CPU,协调整个集群工作。
- Broker(核心服务):最核心、最娇贵、配置最繁琐的组件,负责消息存储、传递、查询。类比电脑硬盘、显卡等核心硬件。
- Client(客户端):包括生产者和消费者。类比键盘、鼠标、显示器等输入输出设备,通过 CPU(NameServer)协调与核心硬件交互。
2. 消息模型核心概念
- Topic(主题):逻辑概念,代表一类有相同业务规则的消息;对 Broker 代表一系列存储资源。默认需管理员手动创建,生产环境不建议开启
autoCreateTopic=true。 - MessageQueue(消息队列):Topic 下的消息分布到多个 MessageQueue,这些队列分布在一个或多个 Broker 上。每个队列具有 FIFO 特性,记录最小位点和最大位点(offset 偏移量)。
- Offset(偏移量):消息在 MessageQueue 上的存储位置索引,新消息按当前最大位点往后分配新位点。
- 消费位点:Broker 端为每个消费者组记录消费进度(Offset),控制消息处理进度,确保每条消息在一个消费者组中只被处理一次。
- 消费者组:RocketMQ 以订阅组为单位记录消费进度,不同消费者组可独立消费同一 Topic 下所有消息。
与 Kafka 对比:RocketMQ 早期借鉴 Kafka,但后续大幅调整。Kafka 中 Topic 过多会导致吞吐量下降,而 RocketMQ 加强了 Topic 支持,Topic 过多几乎不影响性能。
四、面试常见问题与解答
问题 1:什么是消息队列?MQ 的三大核心作用是什么?
解答:消息队列(MQ)是具备消息跨进程传输和队列数据缓存能力的中间件。三大核心作用:
- 异步:生产者发送消息后无需等待消费者处理,提高系统响应速度和吞吐量。
- 解耦:减少服务间直接依赖,提高系统稳定性和可扩展性,支持一对多数据分发。
- 削峰:用稳定的系统资源应对突发流量,避免流量高峰压垮下游系统。
问题 2:RocketMQ 为什么被阿里自研?相比 Kafka 和 RabbitMQ 有什么优势?
解答:阿里早期使用 ActiveMQ 遇 IO 瓶颈,转向 Kafka 后发现其针对日志场景设计,Topic 过多时 Partition 文件过多导致 IO 性能下降,因此自研 RocketMQ。相比 Kafka,RocketMQ 消息可靠性更高,功能更全面(广播消费、延迟队列、死信队列、事务消息等);相比 RabbitMQ,吞吐量高很多。RocketMQ 特别适合金融场景,是少数经受住双十一超大规模高并发考验的 MQ 产品。
问题 3:RocketMQ 的 NameServer 和 Broker 各有什么作用?
解答:NameServer 是命名服务,独立启动,不依赖其他服务,负责协调整个集群,Broker 和客户端都必须指定其地址。Broker 是核心服务,负责消息的存储、传递和查询,是配置最繁琐、最需要保护的组件。类比电脑:NameServer 是 CPU,Broker 是硬盘、显卡等核心硬件,Client 是键盘、鼠标等输入输出设备。
问题 4:RocketMQ 中 Topic、MessageQueue、Offset 之间的关系是什么?
解答:Topic 是逻辑概念,代表一类消息;一个 Topic 的消息会分布到多个 MessageQueue 中,这些队列分布在一个或多个 Broker 上。每条消息存储在某个 MessageQueue 的某个位置,这个位置就是 Offset(偏移量)。消费者通过记录消费位点(Offset)控制消费进度,确保每条消息在一个消费者组中只被处理一次。
问题 5:RocketMQ 主从架构和 Dledger 高可用集群有什么区别?
解答:主从架构中 Master 响应客户端请求,Slave 备份数据,但角色固定,Slave 无法自动升级为 Master,broker 宕机后该节点消息需等待重启才能消费。Dledger 集群基于 Raft 协议自动选举 Leader(类似 Master),Follower 随时准备升级,只要超过半数节点正常工作集群即可工作,实现了服务高可用。但 Dledger 接管文件写入,性能略低于原生方式。
问题 6:Raft 协议如何解决分布式集群的脑裂问题?
解答:Raft 协议通过以下机制避免脑裂:
- 选举机制:候选人必须获得集群大多数节点支持才能成为 Leader,确保集群只有一个 Leader。
- 任期编号:每个选举周期有递增任期,旧 Leader 不会再次当选,节点发现任期落后会停止工作并更新。
- 心跳机制:Leader 定期发送心跳,节点长时间未收到心跳会启动新一轮选举,快速选出新 Leader。
- 日志复制:Follower 必须收到 Leader 日志条目并写入本地后才响应请求,避免脑裂时多个节点同时修改同一数据。
问题 7:RocketMQ 中消费者组的消费进度是如何记录的?
解答:RocketMQ 以消费者组为单位记录消费进度。Broker 端为每个消费者组在每个 MessageQueue 上记录消费位点(Offset),即该组已消费的最大消息偏移量。代理者位点记录队列最大消息偏移量,两者差值表示未处理完的消息。不同消费者组独立记录消费进度,因此多个消费者组可以独立消费同一 Topic 下的所有消息。
问题 8:生产环境中为什么建议手动创建 Topic,而不是开启 autoCreateTopic?
解答:Topic 对 Broker 代表一系列存储资源,如果允许客户端随意创建 Topic,服务端资源管理压力会非常大,可能导致资源浪费和性能问题。生产环境应由运维人员提前规划并手动创建 Topic,确保资源合理分配和管理。autoCreateTopic 仅适用于测试环境。
问题 9:RabbitMQ、Kafka、RocketMQ 的消息模型有什么区别?各自产品有什么区别?分别适合什么样的业务场景?
解答:三者虽然都是消息中间件,但在消息模型、产品特性和适用场景上有明显差异,下面分别说明。
一、消息模型区别
- RabbitMQ 采用 AMQP 协议,基于 Exchange 和 RoutingKey 路由模型:生产者将消息发送到 Exchange(交换机),Exchange 根据 RoutingKey(路由键)和 Binding(绑定关系)将消息路由到一个或多个 Queue(队列),消费者从 Queue 中拉取消息。消息模型灵活,支持多种路由策略(直连、主题、扇形、头匹配),但消息本身不直接绑定 Topic,而是通过 Exchange 间接路由。
- Kafka 采用发布订阅模型,基于 Topic 和 Partition 分区模型:一个 Topic 被划分为多个 Partition(分区),每个 Partition 是一个有序的日志文件,消息按顺序追加写入。同一 Partition 内消息有序,但跨 Partition 不保证全局有序。消费者以 Consumer Group 为单位消费,每个 Partition 在同一时刻只能被组内一个消费者消费,实现负载均衡和水平扩展。
- RocketMQ 采用发布订阅模型,基于 Topic 和 MessageQueue 队列模型:一个 Topic 的消息分布到多个 MessageQueue 中,这些队列分布在一个或多个 Broker 上。每个 MessageQueue 具有 FIFO 特性,记录最小位点和最大位点(Offset)。RocketMQ 早期借鉴 Kafka 的模型,但加强了多 Topic 支持,Topic 过多几乎不影响性能,这是与 Kafka 最大的差异点。
二、产品特性区别
| 对比维度 | RabbitMQ | Kafka | RocketMQ |
|---|---|---|---|
| 开发语言 | Erlang | Scala/Java | Java |
| 吞吐量 | 较低(万级/秒) | 极高(百万级/秒) | 高(十万级/秒),略低于 Kafka |
| 消息可靠性 | 高,支持消息确认机制 | 可能丢数据,可靠性一般 | 高,可靠性优于 Kafka |
| 消息顺序 | 单队列内有序 | 单 Partition 内有序 | 单 MessageQueue 内有序 |
| 高级功能 | 延迟队列、死信队列、优先级队列 | 功能较单一,主要面向日志流 | 广播消费、延迟队列、死信队列、事务消息、定时消息 |
| 多 Topic 支持 | 通过 Exchange 灵活路由 | Topic 过多导致 Partition 文件过多,IO 性能下降 | Topic 过多几乎不影响性能 |
| 可定制性 | Erlang 语言,二次开发门槛高 | Java 生态,可定制性较好 | Java 开发,易定制,社区活跃 |
三、适用业务场景
- RabbitMQ 适合企业内部小规模服务调用:消息可靠性高、功能全面,路由模型灵活,适合对消息可靠性要求高、业务逻辑复杂、消息量不大的场景,如企业内部系统间异步通知、任务调度、订单状态变更通知等。
- Kafka 适合日志分析和大数据采集:吞吐量极大、性能好、集群高可用,适合海量日志收集、用户行为追踪、流式数据处理、大数据管道等对吞吐量要求极高、对消息可靠性要求相对宽松的场景。
- RocketMQ 适合金融互联网等几乎全场景:高吞吐、高性能、高可用,功能全面,消息可靠性优于 Kafka,特别适合金融场景(如交易、支付、风控)、电商订单、物流追踪等对消息可靠性和功能完整性要求高的业务。阿里内部每天处理请求超 5 万亿次,支撑核心应用超 3000 个,是经受住双十一超大规模高并发考验的 MQ 产品。