RocketMQ核心架构解析与实战指南 - 详解
一、了解RocketMQ
1.1 是什么?
RocketMQ 是阿里巴巴开源的分布式消息中间件,Apache 顶级项目,主打高吞吐、低延迟、高可靠,适用于异步通信、削峰填谷、分布式事务等场景(如购票系统、订单系统)。
1.2 核心架构:为什么要分离 NameServer 和 Broker?
这是 RocketMQ 架构设计的核心,本质是解耦 “路由管理” 与 “消息存储转发”,具体原因如下:
| 核心目标 | 具体逻辑 |
|---|---|
| 解耦职责 | NameServer 只做 “路由导航”(存 Broker 地址、Topic 映射),Broker 只做 “消息仓库”(存消息、处理收发),避免功能混杂导致维护困难。 |
| 提升高可用 | NameServer 无状态可集群部署,某个节点宕机不影响整体;Broker 故障时,NameServer 会更新路由表,生产者 / 消费者自动切换,避免 “一损俱损”。 |
| 弹性扩展 | 消息量暴增时,只需新增 Broker 节点(无需动 NameServer);路由请求多则新增 NameServer,按需扩容不浪费资源。 |
简单比喻:NameServer 是 “快递网点导航系统”(告诉你包裹该送哪个网点),Broker 是 “快递网点”(实际收寄包裹)。
二、Rocketmq的几种概念
2.1 组件角色
| 组件 | 核心职责 |
|---|---|
| NameServer | 1. 管理 Broker 路由信息;2. 给生产者 / 消费者提供 “消息在哪” 的查询服务;3. 无状态(不存消息)。 |
| Broker | 1. 存储消息(接收生产者消息,写入磁盘 / 内存);2. 处理消息转发(给消费者推 / 拉消息);3. 支持主从复制(高可用)。 |
| Producer | 消息生产者(如购票系统中 “用户提交订单” 模块,负责发消息到 Broker)。 |
| Consumer | 消息消费者(如购票系统中 “扣减库存” 模块,负责从 Broker 读消息并处理)。 |
2.2 消息相关概念:Topic/Tag/ 消息体的关系
这是高频混淆点 ——Topic 和 Tag 是 “消息元数据”,不属于消息体,三者独立:
| 概念 | 本质 | 作用 | 是否属于消息体(Body) |
|---|---|---|---|
| Topic | 消息一级分类(如 “CONFIRM_ORDER”) | 决定消息路由到哪个 Broker/Queue,是收发消息的 “必选定位标识”。 | 否 |
| Tag | 消息二级分类(如 “TAG_CREATE”) | 同一 Topic 下筛选消息(如只消费 “订单创建” 消息),避免接收无关数据。 | 否 |
| 消息体(Body) | 字节数组(byte []) | 承载业务数据(如ConfirmOrderMQDto序列化后的 JSON),仅生产者 / 消费者约定解析规则。 | 是 |
示例:一条购票消息的结构
- Topic:
CONFIRM_ORDER(标识 “购票相关消息”) - Tag:
TAG_CREATE(标识 “订单创建” 类型) - Body:
{"orderId":123,"trainCode":"G1001"}(实际业务数据)
2.3 其他关键概念
- Queue:每个 Topic 包含多个 Queue(默认 4 个),分布在不同 Broker 上,用于负载均衡(如 4 个 Queue 分给 2 个消费者,各处理 2 个)。
- Offset:消息在 Queue 中的 “位置下标”,消费者通过记录 Offset 确认 “已消费到哪”(如 Offset=100 表示已消费前 100 条)。
- 死信队列:重试多次失败的消息会进入
%DLQ%+消费者组名队列,需手动处理(如订单支付超时消息)。
三、环境搭建:Windows/Linux 快速启动
以 Windows 为例(Linux 流程类似,只需替换脚本后缀为.sh):
3.1 环境准备
- JDK:1.8+(RocketMQ 5.x 支持 JDK 17)
- 安装包:官网下载(推荐 5.0 + 版本)
3.2 配置与启动
- 解压安装包:如解压到
D:\rocketmq-all-5.2.0-bin-release - 修改 Broker 配置(
conf/broker.conf):properties
brokerIP1=127.0.0.1 # 本机IP(集群部署填实际IP) namesrvAddr=127.0.0.1:9876 # NameServer地址 - 启动 NameServer:打开 CMD,进入
bin目录,执行:cmd
成功日志:start mqnamesrv.cmdThe Name Server boot success... - 启动 Broker:新打开 CMD,执行:
cmd
成功日志:start mqbroker.cmd -n 127.0.0.1:9876 -c ../conf/broker.confThe broker[xxx, 127.0.0.1:10911] boot success...
3.3 验证服务
- 发送测试消息:
set NAMESRV_ADDR=127.0.0.1:9876 tools.cmd org.apache.rocketmq.example.quickstart.Producer # 发消息 tools.cmd org.apache.rocketmq.example.quickstart.Consumer # 收消息
四、两种开发方式
RocketMQ 支持原生 API和Spring Boot 集成,后者更简洁(封装了细节),实际开发优先用 Spring Boot。
Spring Boot 集成步骤
1. 引入依赖
org.apache.rocketmq
rocketmq-spring-boot-starter
2.2.3
2. 配置文件(application.yml)
rocketmq:
name-server: 127.0.0.1:9876 # NameServer地址(必填)
producer:
group: my-producer-group # 生产者组(必填,标识同一类生产者)
send-message-timeout: 3000 # 发送超时时间(毫秒)
五、发送方法
在 RocketMQ 中,消息发送方法的核心差异体现在 “可靠性”“阻塞性”“业务特性” 三个维度。根据不同的业务需求(如是否需要确认结果、是否有定时 / 事务需求),需选择合适的发送方法。以下从 “基础发送方式” 和 “特殊消息类型” 两方面详细讲解,结合实战场景说明用法和区别。
5.1基础发送方式(按 “可靠性与阻塞性” 分类)
这是最常用的三种发送方式,核心区别在于 “是否等待 Broker 响应” 和 “是否阻塞当前线程”。
1. 同步发送(Sync Send)
定义
发送消息后,阻塞当前线程,等待 Broker 返回确认结果(SendResult),直到超时或收到响应。
核心特点
- 可靠性高:明确知道消息是否成功送达(成功 / 失败 / 超时);
- 性能中等:因阻塞等待,TPS 低于异步发送;
- 适用场景:核心业务(如订单创建、支付通知),必须确保消息不丢失且知道结果。
原生 API 实现(DefaultMQProducer)
// 创建生产者
DefaultMQProducer producer = new DefaultMQProducer("sync-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 构建消息(Topic、Tag、Body)
Message msg = new Message(
"order-topic", // Topic
"create", // Tag(可选)
"订单ID:1001".getBytes() // 消息体(字节数组)
);
// 同步发送(等待结果)
SendResult result = producer.send(msg); // 超时默认3000ms,可指定:send(msg, 5000)
if (result.getSendStatus() == SendStatus.SEND_OK) {
System.out.println("发送成功,消息ID:" + result.getMsgId());
} else {
System.out.println("发送失败:" + result.getSendStatus());
}
producer.shutdown();
Spring Boot 封装实现(RocketMQTemplate)
@Autowired
private RocketMQTemplate rocketMQTemplate;
// 方式1:convertAndSend(自动序列化POJO,简化版同步发送)
public void sendSync1() {
OrderDTO order = new OrderDTO(1001L, "手机");
// 自动将OrderDTO转为JSON,发送到"order-topic:create"
rocketMQTemplate.convertAndSend("order-topic:create", order);
}
// 方式2:syncSend(更灵活,支持自定义超时、延迟等)
public void sendSync2() {
OrderDTO order = new OrderDTO(1001L, "手机");
// 自定义超时时间3秒
SendResult result = rocketMQTemplate.syncSend("order-topic:create", order, 3000);
if (result.getSendStatus() == SendStatus.SEND_OK) {
System.out.println("发送成功");
}
}
2. 异步发送(Async Send)
定义
发送消息后 不阻塞当前线程,立即返回,通过回调函数(SendCallback)异步处理 Broker 的响应结果(成功 / 失败)。
核心特点
- 可靠性高:同样能获取发送结果,但通过异步回调处理;
- 性能高:非阻塞,适合高并发场景;
- 适用场景:响应时间敏感的业务(如用户 APP 提交订单后,无需等待库存扣减完成即可显示 “提交中”)。
原生 API 实现
DefaultMQProducer producer = new DefaultMQProducer("async-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message msg = new Message("order-topic", "pay", "订单支付:1001".getBytes());
// 异步发送,通过回调处理结果
producer.sendAsync(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("异步发送成功,消息ID:" + sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
System.err.println("异步发送失败:" + e.getMessage());
// 失败处理:如重试、记录日志
}
});
// 注意:异步发送后需保持生产者运行(实际项目中无需手动shutdown,由Spring管理)
// producer.shutdown();
Spring Boot 封装实现
public void sendAsync() {
OrderDTO order = new OrderDTO(1001L, "手机");
// 异步发送,回调处理结果
rocketMQTemplate.asyncSend("order-topic:pay", order, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("异步发送成功");
}
@Override
public void onException(Throwable e) {
System.err.println("异步发送失败");
}
});
}
3. 单向发送(Oneway Send)
定义
发送消息后 不等待任何响应,直接返回,Broker 是否收到消息完全未知。
核心特点
- 可靠性低:可能丢失消息(如网络故障、Broker 宕机);
- 性能极高:无阻塞、无回调,适合超高频发送;
- 适用场景:非核心业务(如日志收集、监控数据上报),允许偶尔丢失消息。
原生 API 实现
DefaultMQProducer producer = new DefaultMQProducer("oneway-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message msg = new Message("log-topic", "user", "用户1001登录".getBytes());
// 单向发送,不关心结果
producer.sendOneway(msg);
producer.shutdown();
Spring Boot 封装实现
public void sendOneway() {
// 发送日志消息,不关心结果
rocketMQTemplate.sendOneWay("log-topic:user", "用户1001登录");
}
5.2特殊消息类型(按 “业务特性” 分类)
针对特定业务场景(如定时任务、分布式事务、顺序依赖),RocketMQ 提供了专用发送方法。
1. 延迟消息(Delay Message)
定义
消息发送后,Broker 不会立即投递,而是 延迟指定时间后 再推送给消费者(如 “订单 30 分钟未支付自动取消”)。
核心特点
- 延迟时间通过 “延迟级别” 控制(默认 18 级,如 1 级 = 1s、2 级 = 5s、3 级 = 10s...18 级 = 2h,可自定义配置);
- 本质是 “临时存储 + 定时投递”:消息先存到 “延迟队列”,到达时间后转移到目标 Topic。
实现方式(Spring Boot)
public void sendDelay() {
OrderDTO order = new OrderDTO(1001L, "手机");
// 发送延迟消息:延迟级别3(默认10秒),超时时间3秒
rocketMQTemplate.syncSend(
"order-delay-topic", // Topic
order, // 消息体
3000, // 超时时间
3 // 延迟级别(3级=10秒)
);
}
注意
- 延迟级别需在 Broker 配置文件(
broker.conf)中定义,默认配置:messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h - 延迟消息不支持任意时间(如 “7 秒”),需按级别定义。
2. 事务消息(Transaction Message)
定义
解决分布式事务问题:通过 “半事务消息 + 本地事务 + 事务回查” 机制,确保跨服务操作的一致性(如 “下单” 和 “减库存” 要么都成功,要么都失败)。
核心流程
- 发送 “半事务消息”(Broker 标记为 “待确认”,暂不投递);
- 执行本地事务(如 “创建订单”);
- 根据本地事务结果,发送 “提交” 或 “回滚” 指令(Broker 收到 “提交” 后投递消息,“回滚” 则删除消息);
- 若本地事务结果未知(如超时),Broker 会主动回查生产者,确认最终状态。
实现方式(Spring Boot)
// 1. 发送事务消息
public void sendTransaction() {
OrderDTO order = new OrderDTO(1001L, "手机");
// 参数:生产者组、Topic:Tag、消息体、自定义业务参数
rocketMQTemplate.sendMessageInTransaction(
"order-tx-group", // 事务生产者组(需与监听器一致)
"order-tx-topic:create", // Topic:Tag
order, // 消息体
null // 自定义参数(如订单ID)
);
}
// 2. 定义事务监听器(处理本地事务和回查)
@RocketMQTransactionListener(txProducerGroup = "order-tx-group") // 与生产者组一致
public class OrderTxListener implements RocketMQLocalTransactionListener {
// 执行本地事务(如创建订单)
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
try {
// 本地事务逻辑:如插入订单表
OrderDTO order = JSON.parseObject(new String((byte[]) msg.getPayload()), OrderDTO.class);
orderMapper.insert(order); // 假设插入订单
return RocketMQLocalTransactionState.COMMIT; // 本地事务成功,提交消息
} catch (Exception e) {
return RocketMQLocalTransactionState.ROLLBACK; // 本地事务失败,回滚消息
}
}
// 事务回查(Broker查询本地事务状态)
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
OrderDTO order = JSON.parseObject(new String((byte[]) msg.getPayload()), OrderDTO.class);
// 检查订单是否存在:存在则提交,不存在则回滚
OrderDTO dbOrder = orderMapper.selectById(order.getId());
return dbOrder != null ? RocketMQLocalTransactionState.COMMIT : RocketMQLocalTransactionState.ROLLBACK;
}
3. 顺序消息(Ordered Message)
定义
确保消息 按发送顺序被消费(如同一订单的 “创建→支付→发货” 消息必须按顺序处理)。
核心原理
- RocketMQ 中 “单个 Queue 内的消息是有序的”,但 Topic 包含多个 Queue(默认 4 个);
- 发送时通过 “业务标识”(如订单 ID)将同一类消息路由到 同一个 Queue,消费时按 Queue 顺序处理。
实现方式(Spring Boot)
public void sendOrderly() {
String orderId = "ORDER_1001"; // 业务标识(同一订单ID)
// 发送3条同一订单的消息,确保顺序
rocketMQTemplate.syncSendOrderly(
"order-seq-topic", // Topic
"创建订单:" + orderId, // 消息1
orderId // 路由key(同一key进入同一Queue)
);
rocketMQTemplate.syncSendOrderly("order-seq-topic", "支付订单:" + orderId, orderId); // 消息2
rocketMQTemplate.syncSendOrderly("order-seq-topic", "发货订单:" + orderId, orderId); // 消息3
}
// 消费者(需确保同一Queue被同一消费者处理)
@RocketMQMessageListener(
topic = "order-seq-topic",
consumerGroup = "order-seq-group",
consumeMode = ConsumeMode.ORDERLY // 顺序消费模式(默认是并发模式)
)
public class OrderSeqConsumer implements RocketMQListener {
@Override
public void onMessage(String message) {
System.out.println("顺序消费:" + message); // 按“创建→支付→发货”顺序输出
}
}
注意
- 消费者需设置
consumeMode = ConsumeMode.ORDERLY(默认是CONCURRENTLY并发模式); - 顺序消息会降低消费吞吐量(单 Queue 无法并行处理),非必要不使用。
5.3发送方法对比
| 发送方式 | 阻塞性 | 可靠性 | 性能 | 核心场景 | 关键 API(Spring) |
|---|---|---|---|---|---|
| 同步发送 | 阻塞 | 高 | 中 | 核心业务(订单、支付) | convertAndSend、syncSend |
| 异步发送 | 非阻塞 | 高 | 高 | 响应敏感场景(用户交互) | asyncSend |
| 单向发送 | 非阻塞 | 低 | 极高 | 非核心消息(日志、监控) | sendOneWay |
| 延迟消息 | 可阻塞 | 高 | 中 | 定时任务(超时取消) | syncSend(带 delayLevel) |
| 事务消息 | 可阻塞 | 最高 | 中 | 分布式事务(跨服务一致性) | sendMessageInTransaction |
| 顺序消息 | 可阻塞 | 高 | 中 | 有序依赖(订单流程) | syncSendOrderly |
5.4应用场景
- 同步发送:订单创建通知库存扣减、支付结果同步订单状态、金融交易指令对账
- 异步发送:APP 下单后快速响应前端、秒杀活动流量削峰、批量非实时数据同步
- 单向发送:用户行为日志收集、系统监控指标上报、非关键浏览记录上报
- 延迟消息:订单超时未支付自动取消、会议前定时提醒、接口失败延迟重试
- 事务消息:下单扣库存(跨服务一致性)、银行转账(A 扣钱 B 加钱)、积分兑换商品
- 顺序消息:同一订单的创建→支付→发货流程、物流状态流转(已揽收→运输中→签收)、有序操作日志记录
六、通过RocketMQ在项目中实现异步购票逻辑
6.1 整体架构
用户发起购票请求 → BeforeConfirmOrderService(前置校验+发MQ) → RocketMQ → ConfirmOrderConsumer(消费消息+实际购票)
6.2 关键步骤代码解析
1. 前置校验与消息发送(BeforeConfirmOrderService)
@Service
public class BeforeConfirmOrderService {
@Autowired
private RocketMQTemplate rocketMQTemplate;
public Long beforeDoConfirm(ConfirmOrderDoReq req) {
// 1. 发送MQ消息(异步触发实际购票,避免用户等待)
ConfirmOrderMQDto dto = new ConfirmOrderMQDto();
dto.setOrderId(confirmOrder.getId());
dto.setTrainCode(req.getTrainCode());
// 自动转换DTO为Message,发送到CONFIRM_ORDER Topic
rocketMQTemplate.convertAndSend(RocketMQTopicEnum.CONFIRM_ORDER.getCode(), dto);
return confirmOrder.getId(); // 快速返回,用户无需等待购票完成
}
}
2. 消息消费与实际购票(ConfirmOrderConsumer)
@Component
@RocketMQMessageListener(
topic = "CONFIRM_ORDER", // 监听发送的Topic
consumerGroup = "confirm-order-consumer-group"
)
public class ConfirmOrderConsumer implements RocketMQListener {
@Autowired
private ConfirmOrderService confirmOrderService;
@Override
public void onMessage(ConfirmOrderMQDto dto) {
// 实际购票逻辑:扣减库存、更新订单状态为“已确认”
confirmOrderService.doConfirm(dto);
}
}
6.3 RocketMQ 在案例中的价值
- 削峰填谷:高并发抢票时,请求先进入 MQ 队列,消费者按能力处理,避免系统过载;
- 异步解耦:用户无需等待 “扣减库存” 完成,快速收到响应,提升体验;
- 可靠性保障:即使消费者故障,MQ 会持久化消息,重启后继续处理,避免购票请求丢失。
浙公网安备 33010602011771号