一、RocketMQ 核心原理详解
1.1 概述与定位
Apache RocketMQ 是一个纯Java、分布式、队列模型的开源消息中间件。它最初由阿里巴巴团队研发,用于解决内部超大规模电商场景(如双十一)下的消息通信问题,后于2016年捐献给Apache基金会,成为顶级开源项目。
其核心设计目标是成为一款 "金融级可靠、高吞吐、低延迟、功能丰富" 的消息中间件。它平衡了可靠性与性能,原生支持事务消息、顺序消息等高级特性,在国内互联网、金融、电商领域被广泛采用,也是Spring Cloud Alibaba生态的首选。
1.2 架构设计
RocketMQ的架构设计简洁,主要包含四大核心组件,5.0版本后新增了Proxy组件以实现云原生化升级。采用分布式集群架构,主要由以下四个核心组件构成:
┌─────────────────────────────────────────────────────────────┐
│ NameServer 集群 │
│ (服务注册与发现,无状态,可横向扩展) │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ Broker Master │◄──►│ Broker Master │◄──►│ Broker Master │
│ [Broker Slave]│ │ [Broker Slave]│ │ [Broker Slave]│
│ (Topic A-C) │ │ (Topic D-F) │ │ (Topic G-I) │
└───────────────┘ └───────────────┘ └───────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Producer & Consumer │
└─────────────────────────────────────────────────────────────┘
核心组件说明
|----------------|--------------------------------------|--------------------------------------|
| 组件 | 角色与职责 | 关键特性 |
| NameServer | 轻量级路由注册中心,管理Broker与Topic的路由映射关系。 | 无状态,节点间无需同步,可水平扩展,部署简单。 |
| Broker | 消息存储与转发的核心。负责消息的接收、持久化、消费拉取等。 | 支持Master-Slave主从架构,保证数据高可用。5.0后专注存储。 |
| Proxy | 无状态计算层(5.0新增)。负责协议适配、权限管理、消费管控等。 | 实现存储与计算解耦,更适配K8s等云原生环境,支持独立弹性伸缩。 |
| Producer | 消息生产者,集成于业务系统,发送消息。 | 支持同步、异步、单向三种发送模式。 |
| Consumer | 消息消费者,从Broker拉取消息进行业务处理。 | 支持集群消费和广播消费两种模式。 |
核心概念
- Topic(主题):消息的第一级分类,用于标识一类业务逻辑。5.0版本后一个Topic仅允许一种消息类型。
- MessageQueue(消息队列):消息的实际存储单元,每个Topic由多个Queue组成,实现水平拆分和并行处理。队列内部严格有序。
- ConsumerGroup(消费者组):逻辑上的消费者集合,实现负载均衡和高可用。组内的多个Consumer共同消费Topic下的队列,一个消息只会被组内一个Consumer消费。
- Tag(消息标签):消息的第二级分类,用于在同一Topic下做更细粒度的区分。Consumer可通过订阅Tag在Broker端完成消息过滤,提升效率。
- Message(消息):数据传输的最小单元,包含消息体、Key(业务唯一标识,便于检索)、Tag等属性。
1.3 消息存储机制(核心亮点)
RocketMQ 使用CommitLog + ConsumeQueue 的存储架构,这是其高性能的关键:
存储结构图解
┌─────────────────────────────────────────────────────────────┐
│ CommitLog (顺序写) │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────────────┐ │
│ │Message 1│Message 2│Message 3│Message 4│ ... │ │
│ │(所有Topic│(所有Topic│(所有Topic│(所有Topic│ │ │
│ │ 混合存储)│ 混合存储)│ 混合存储)│ 混合存储)│ │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────────────┘ │
│ 磁盘顺序写入,极高吞吐量 │
└─────────────────────────────────────────────────────────────┘
│
▼ 构建索引
┌─────────────────────────────────────────────────────────────┐
│ ConsumeQueue (逻辑队列) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Topic A │ │ Topic B │ │ Topic C │ │
│ │ Queue 0 │ │ Queue 0 │ │ Queue 0 │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │CommitLog│ │ │ │CommitLog│ │ │ │CommitLog│ │ │
│ │ │Offset │ │ │ │Offset │ │ │ │Offset │ │ │
│ │ │Size │ │ │ │Size │ │ │ │Size │ │ │
│ │ │Tag Hash │ │ │ │Tag Hash │ │ │ │Tag Hash │ │ │
│ │ │(20字节) │ │ │ │(20字节) │ │ │ │(20字节) │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ │ ... │ │ ... │ │ ... │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ 定长存储,支持随机读取,加速消息消费 │
└─────────────────────────────────────────────────────────────┘
存储流程详解
-
消息写入:Producer 发送消息 → Broker 顺序写入 CommitLog
-
索引构建:后台线程异步构建 ConsumeQueue 和 IndexFile
-
消息读取:Consumer 通过 ConsumeQueue 定位 CommitLog 中的消息
1.4 高可用机制
主从复制模式演进
| 版本 | 复制模式 | 数据一致性 | 适用场景 |
|---|---|---|---|
| 3.x | 异步复制 | 最终一致 | 高吞吐,容忍秒级丢失 |
| 4.x | 同步双写 | 强一致 | 金融级可靠性 |
| 5.x | DLedger 模式 | Raft 共识 | 自动故障转移 |
DLedger 架构(RocketMQ 5.x)
┌─────────────────────────────────────────────────────────────┐
│ DLedger CommitLog │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Leader │◄────►│ Follower│◄────►│ Follower│ │
│ │ (Master)│ │(Slave-1)│ │(Slave-2)│ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ │
│ │ Raft 协议选举与复制 │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ 写入需多数派确认 (W > N/2) │ │
│ │ Leader 故障自动选举新 Leader │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1.5 高级特性
1.5.1 事务消息:分布式一致性
用于解决分布式系统中本地事务与消息发送的一致性问题(如订单创建成功后,确保支付消息发送成功)。
原理:基于两阶段提交与事务回查。
- Producer发送"半事务消息"至Broker(暂不可见)。
- Producer执行本地事务。
- Producer根据本地事务结果,向Broker发送Commit或Rollback。若为Commit,消息变为对消费者可见。
- 若Producer未明确结果(或网络异常),Broker会定期向Producer发起"事务回查",直到获取最终状态。
1.5.2 顺序消息
保证消息的消费顺序与发送顺序一致。
原理 :通过MessageGroup(消息组)将需要保证顺序的消息发送到同一个MessageQueue 中。同时,Consumer对该队列采用单线程消费,从而保证严格的FIFO顺序。
.3 定时/延时消息
消息发送后,不在立即投递,而是在指定的时间后才对消费者可见。
原理 :消息发送时设置setDeliveryTimestamp。消息到达Broker后,会先存储在基于时间的存储系统中,到达指定时间后才被写入常规存储引擎,供消费者拉取。
二、适用场景分析
2.1 场景决策矩阵
高吞吐量
▲
│
日志采集 ──────────┼────────── 实时计算
(Kafka更优) │ (RocketMQ更优)
│
◄──────────────────┼──────────────────►
简单消息场景 │ 复杂业务场景
│
轻量级MQ ──────────┼────────── 金融级消息
(RabbitMQ) │ (RocketMQ)
│
▼
高可靠性
2.2 RocketMQ 核心适用场景
场景一:金融级可靠消息(首选)
场景特征:支付订单、账务处理、资金划转
┌─────────────────────────────────────────────────────────────┐
│ 支付服务 ──► 事务消息 ──► 账户服务 ──► 通知服务 │
│ │ │ │ │ │
│ │ 1.发送Half消息 │ │ │
│ │ 2.执行本地事务 │ │ │
│ │ 3.提交/回滚消息 │ │ │
│ │ │ │ │ │
│ └───────────┴───────────┴───────────┘ │
│ 全流程消息轨迹追踪 │
└─────────────────────────────────────────────────────────────┘
场景二:大规模分布式事务
场景特征:电商下单、库存扣减、积分累计
┌─────────────────────────────────────────────────────────────┐
│ 订单服务 (TM) │
│ │ │
│ ├──► 发送事务消息:创建订单 │
│ │ │
│ ├──► 本地事务:保存订单记录 │
│ │ │
│ └──► 消息驱动下游服务: │
│ ├──► 库存服务:扣减库存 │
│ ├──► 积分服务:增加积分 │
│ └──► 物流服务:创建运单 │
│ │
│ 异常回滚:本地事务失败 → 回滚消息 → 下游服务不执行 │
└─────────────────────────────────────────────────────────────┘
场景三:实时数据管道
场景特征:日志聚合、监控数据、点击流分析
┌─────────────────────────────────────────────────────────────┐
│ 应用集群 ──► RocketMQ ──► Flink/Spark ──► 实时大屏/告警 │
│ │
│ 特性利用: │
│ • 批量消息:提升吞吐 │
│ • 延迟消息:定时任务调度 │
│ • 消息过滤:Tag机制减少网络传输 │
└─────────────────────────────────────────────────────────────┘
场景四:定时/延迟任务
场景特征:订单超时取消、延迟通知、定时触发
┌─────────────────────────────────────────────────────────────┐
│ 延迟级别(默认18级): │
│ 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h │
│ │
│ 使用方式: │
│ message.setDelayTimeLevel(3); // 10秒后投递 │
│ │
│ RocketMQ 5.x 支持任意时间延迟: │
│ message.setDelayTimeMs(15000); // 15秒后投递 │
└─────────────────────────────────────────────────────────────┘
2.3 版本选型建议
表格
| 版本 | 推荐度 | 核心特性 | 建议升级路径 |
|---|---|---|---|
| 4.9.x | ⭐⭐⭐⭐ | 稳定成熟,社区活跃 | 存量系统维护 |
| 5.0.x | ⭐⭐⭐ | 全新架构,Proxy模式 | 谨慎试点 |
| 5.1.x+ | ⭐⭐⭐⭐⭐ | 生产就绪,Pop消费 | 新系统首选 |
三、Spring Boot 集成实战(版本号精确到补丁)
3.1 版本兼容性矩阵
┌─────────────────────────────────────────────────────────────┐
│ Spring Boot 与 RocketMQ 版本对应 │
├──────────────────┬──────────────────┬───────────────────────┤
│ Spring Boot │ RocketMQ-Spring │ RocketMQ Server │
├──────────────────┼──────────────────┼───────────────────────┤
│ 2.3.x │ 2.2.3 │ 4.9.4+ │
│ 2.4.x │ 2.2.4 │ 4.9.4+ │
│ 2.5.x │ 2.2.5 │ 4.9.4+ │
│ 2.6.x │ 2.2.6 │ 4.9.4+ │
│ 2.7.x │ 2.2.7 │ 4.9.4 / 5.0.x │
│ 3.0.x │ 2.2.8 │ 5.1.0+ │
│ 3.1.x │ 2.2.9 │ 5.1.3+ │
│ 3.2.x │ 2.3.0 │ 5.2.0+ │
└──────────────────┴──────────────────┴───────────────────────┘
3.2 完整集成示例(Spring Boot 2.7.18 + RocketMQ 5.1.4)
3.2.1 Maven 依赖配置
<!-- pom.xml -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<properties>
<rocketmq-spring-boot-starter.version>2.2.7</rocketmq-spring-boot-starter.version>
<rocketmq-client.version>5.1.4</rocketmq-client.version>
</properties>
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- RocketMQ Spring Boot Starter -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq-spring-boot-starter.version}</version>
</dependency>
<!-- 显式指定客户端版本(覆盖starter中的版本) -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>${rocketmq-client.version}</version>
</dependency>
<!-- 使用ACL时需要 -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<version>${rocketmq-client.version}</version>
</dependency>
</dependencies>
3.2.2 配置文件(application.yml)
rocketmq:
# NameServer 地址,集群用分号分隔
name-server: 192.168.1.100:9876;192.168.1.101:9876
# Producer 配置
producer:
group: order-service-producer-group
# 发送超时时间(毫秒)
send-message-timeout: 3000
# 消息压缩阈值(字节)
compress-message-body-threshold: 4096
# 最大消息大小(字节)
max-message-size: 4194304
# 重试次数(同步发送)
retry-times-when-send-failed: 2
# 重试次数(异步发送)
retry-times-when-send-async-failed: 2
# 是否启用VIP通道
vip-channel-enabled: false
# Consumer 配置
consumer:
# 默认消费者组
group: order-service-consumer-group
# 消费线程数
consume-thread-min: 20
consume-thread-max: 64
# 消费超时时间(分钟)
consume-timeout: 15
# 最大重试次数
max-reconsume-times: 16
# 消费模式:CONCURRENTLY(并发)/ ORDERLY(顺序)
consume-mode: CONCURRENTLY
# 消息模式:CLUSTERING(集群)/ BROADCASTING(广播)
message-model: CLUSTERING
# 开启消息轨迹(需要服务端支持)
trace-enabled: true
3.2.3 生产者实现
/**
* 订单消息生产者
* 版本:RocketMQ Client 5.1.4
*/
@Service
@Slf4j
public class OrderMessageProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
// Topic 常量定义
private static final String ORDER_TOPIC = "ORDER_TOPIC";
private static final String ORDER_TAG_CREATE = "CREATE";
private static final String ORDER_TAG_PAY = "PAY";
private static final String ORDER_TAG_CANCEL = "CANCEL";
/**
* 同步发送普通消息(可靠投递)
*/
public SendResult sendOrderCreatedMessage(Order order) {
Message<Order> message = MessageBuilder
.withPayload(order)
.setHeader("KEYS", order.getOrderId()) // 业务Key
.setHeader("TRANSACTION_ID", order.getTransactionId())
.build();
try {
// 同步发送,等待Broker确认
SendResult sendResult = rocketMQTemplate.syncSend(
ORDER_TOPIC + ":" + ORDER_TAG_CREATE, // Topic:Tag
message,
3000 // 超时3秒
);
if (!sendResult.getSendStatus().equals(SendStatus.SEND_OK)) {
log.error("消息发送失败,状态:{}", sendResult.getSendStatus());
throw new MessageSendException("消息发送失败");
}
log.info("订单创建消息发送成功,orderId={}, msgId={}",
order.getOrderId(), sendResult.getMsgId());
return sendResult;
} catch (Exception e) {
log.error("订单创建消息发送异常", e);
throw new MessageSendException("消息发送异常", e);
}
}
/**
* 异步发送消息(高吞吐场景)
*/
public void sendOrderPayMessageAsync(Order order) {
Message<Order> message = MessageBuilder
.withPayload(order)
.setHeader("KEYS", order.getOrderId())
.build();
rocketMQTemplate.asyncSend(
ORDER_TOPIC + ":" + ORDER_TAG_PAY,
message,
new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("异步发送成功,msgId={}", sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
log.error("异步发送失败,orderId={}", order.getOrderId(), e);
// 补偿逻辑:记录失败消息,定时重试
}
},
3000
);
}
/**
* 发送延迟消息(订单超时取消)
* RocketMQ 5.x 支持任意延迟时间
*/
public void sendDelayCancelMessage(Order order, long delayMillis) {
Message<Order> message = MessageBuilder
.withPayload(order)
.setHeader("KEYS", order.getOrderId())
.build();
// RocketMQ 5.1.4 支持延迟消息
rocketMQTemplate.syncSendDelayTimeSeconds(
ORDER_TOPIC + ":" + ORDER_TAG_CANCEL,
message,
delayMillis / 1000 // 转换为秒
);
}
/**
* 发送顺序消息(保证分区有序)
*/
public void sendOrderlyMessage(Order order) {
// 根据用户ID选择队列,保证同一用户订单有序
String hashKey = String.valueOf(order.getUserId() % 100);
rocketMQTemplate.syncSendOrderly(
ORDER_TOPIC + ":" + ORDER_TAG_CREATE,
MessageBuilder.withPayload(order).build(),
hashKey // 队列选择Key
);
}
/**
* 发送事务消息(分布式事务)
*/
public TransactionSendResult sendTransactionMessage(Order order) {
Message<Order> message = MessageBuilder
.withPayload(order)
.setHeader("KEYS", order.getOrderId())
.setHeader("TRANSACTION_ID", order.getTransactionId())
.build();
return rocketMQTemplate.sendMessageInTransaction(
"order-tx-producer-group",
ORDER_TOPIC + ":" + ORDER_TAG_CREATE,
message,
order // 本地事务参数
);
}
/**
* 批量发送(日志采集场景)
*/
public void sendBatchMessages(List<Order> orders) {
List<Message<?>> messages = orders.stream()
.map(order -> MessageBuilder.withPayload(order).build())
.collect(Collectors.toList());
rocketMQTemplate.syncSend(ORDER_TOPIC, messages, 10000);
}
}
3.2.4 消费者实现
/**
* 订单消息消费者
* 消费组:order-service-consumer-group
*/
@Service
@RocketMQMessageListener(
topic = "ORDER_TOPIC",
selectorExpression = "CREATE||PAY", // 订阅多个Tag
consumerGroup = "order-service-consumer-group",
consumeMode = ConsumeMode.CONCURRENTLY, // 并发消费
messageModel = MessageModel.CLUSTERING, // 集群模式
maxReconsumeTimes = 16,
consumeTimeout = 15 // 分钟
)
@Slf4j
public class OrderMessageConsumer implements RocketMQListener<Order>,
RocketMQPushConsumerLifecycleListener {
@Autowired
private OrderService orderService;
/**
* 消息消费逻辑
*/
@Override
public void onMessage(Order order) {
log.info("收到订单消息,orderId={}, status={}",
order.getOrderId(), order.getStatus());
try {
// 幂等性检查(基于业务唯一键)
if (orderService.isProcessed(order.getOrderId())) {
log.warn("消息已处理,跳过,orderId={}", order.getOrderId());
return;
}
// 业务处理
switch (order.getStatus()) {
case "CREATED":
handleOrderCreated(order);
break;
case "PAID":
handleOrderPaid(order);
break;
default:
log.warn("未知订单状态,orderId={}", order.getOrderId());
}
// 记录已处理(幂等)
orderService.markProcessed(order.getOrderId());
} catch (Exception e) {
log.error("订单处理失败,orderId={}", order.getOrderId(), e);
// 抛出异常触发重试
throw new RuntimeException("订单处理失败", e);
}
}
/**
* 消费者生命周期配置
*/
@Override
public void prepareStart(DefaultMQPushConsumer consumer) {
// 设置消费线程数
consumer.setConsumeThreadMin(20);
consumer.setConsumeThreadMax(64);
// 设置每次拉取消息数量
consumer.setPullBatchSize(32);
// 设置消费位点:从最新位置开始(新集群首次启动)
// consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
// 设置消费超时(消息重试阈值)
consumer.setConsumeTimeout(15);
log.info("订单消费者配置完成,consumerGroup={}", consumer.getConsumerGroup());
}
private void handleOrderCreated(Order order) {
// 创建订单后续处理:库存预占、优惠券锁定等
orderService.processOrderCreated(order);
}
private void handleOrderPaid(Order order) {
// 支付成功处理:扣减库存、发放积分、通知物流
orderService.processOrderPaid(order);
}
}
3.2.5 事务消息监听器(分布式事务)
/**
* 订单事务消息监听器
* 实现本地事务与消息的最终一致性
*/
@RocketMQTransactionListener(txProducerGroup = "order-tx-producer-group")
@Slf4j
public class OrderTransactionListener implements RocketMQLocalTransactionListener {
@Autowired
private OrderService orderService;
@Autowired
private TransactionLogService transactionLogService;
/**
* 执行本地事务
* 返回值:COMMIT(提交)、ROLLBACK(回滚)、UNKNOWN(未知,需回查)
*/
@Override
public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Order order = (Order) arg;
String transactionId = msg.getTransactionId();
try {
log.info("执行本地事务,transactionId={}, orderId={}",
transactionId, order.getOrderId());
// 1. 记录事务日志(用于幂等和回查)
transactionLogService.save(TransactionLog.builder()
.transactionId(transactionId)
.orderId(order.getOrderId())
.status("PROCESSING")
.build());
// 2. 执行本地业务(创建订单)
orderService.createOrder(order);
// 3. 更新事务日志状态
transactionLogService.updateStatus(transactionId, "SUCCESS");
log.info("本地事务执行成功,提交消息,transactionId={}", transactionId);
return RocketMQLocalTransactionState.COMMIT;
} catch (Exception e) {
log.error("本地事务执行失败,回滚消息,transactionId={}", transactionId, e);
transactionLogService.updateStatus(transactionId, "FAILED");
return RocketMQLocalTransactionState.ROLLBACK;
}
}
/**
* 本地事务回查(Broker触发)
* 用于处理执行本地事务时超时或崩溃的场景
*/
@Override
public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
String transactionId = msg.getTransactionId();
log.info("本地事务回查,transactionId={}", transactionId);
TransactionLog log = transactionLogService.findById(transactionId);
if (log == null) {
// 事务日志不存在,可能本地事务未执行,回滚
log.warn("事务日志不存在,回滚消息,transactionId={}", transactionId);
return RocketMQLocalTransactionState.ROLLBACK;
}
switch (log.getStatus()) {
case "SUCCESS":
return RocketMQLocalTransactionState.COMMIT;
case "FAILED":
return RocketMQLocalTransactionState.ROLLBACK;
case "PROCESSING":
default:
// 仍在处理中,返回UNKNOWN,等待下次回查
return RocketMQLocalTransactionState.UNKNOWN;
}
}
}
3.3 Spring Boot 3.x 配置差异(版本 3.2.0+)
<!-- Spring Boot 3.2.0 + RocketMQ 5.2.0 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!-- 注意:Spring Boot 3.x 需要 Jakarta EE 命名空间 -->
</dependencies>
// Spring Boot 3.x 消费者配置变化
@RocketMQMessageListener(
topic = "ORDER_TOPIC",
consumerGroup = "order-consumer-group",
// 新增:Pop 消费模式(RocketMQ 5.x 特性)
consumeMode = ConsumeMode.POP, // 替代传统的 Push/Pull
// 新增:消息可见时间(Pop模式)
invisibleTime = 10000 // 毫秒
)
四、企业级案例实战
4.1 案例:电商订单全链路消息驱动
架构设计
┌─────────────────────────────────────────────────────────────┐
│ 网关层 │
│ (Nginx / Spring Cloud Gateway) │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 订单服务 (Order Service) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ API 层:创建订单接口 │ │
│ │ ├─ 参数校验 │ │
│ │ ├─ 生成订单号(雪花算法) │ │
│ │ └─ 发送事务消息(订单创建事件) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ RocketMQ 集群 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ ORDER_TOPIC │ │ STOCK_TOPIC │ │ NOTIFY_TOPIC│ │
│ │ (订单事件) │ │ (库存事件) │ │ (通知事件) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 库存服务 │ │ 支付服务 │ │ 通知服务 │
│ (扣减库存) │ │ (处理支付) │ │ (短信/邮件) │
└─────────────┘ └─────────────┘ └─────────────┘
核心代码实现
/**
* 订单创建流程编排( Saga 模式 + 事务消息)
*/
@Service
@Slf4j
public class OrderSagaOrchestrator {
@Autowired
private OrderMessageProducer producer;
@Autowired
private OrderRepository orderRepository;
/**
* 创建订单(分布式事务入口)
*/
@Transactional(rollbackFor = Exception.class)
public OrderCreateResult createOrder(CreateOrderRequest request) {
// 1. 生成订单号
String orderId = generateOrderId();
// 2. 初始化订单状态
Order order = Order.builder()
.orderId(orderId)
.userId(request.getUserId())
.amount(request.getAmount())
.status(OrderStatus.CREATING)
.createTime(LocalDateTime.now())
.build();
orderRepository.save(order);
// 3. 发送事务消息(关键步骤)
TransactionSendResult txResult = producer.sendTransactionMessage(order);
if (txResult.getLocalTransactionState() != LocalTransactionState.COMMIT_MESSAGE) {
throw new OrderException("订单创建事务提交失败");
}
return OrderCreateResult.builder()
.orderId(orderId)
.status(OrderStatus.CREATING)
.build();
}
}
/**
* 库存服务消费者(TCC 模式实现)
*/
@Service
@RocketMQMessageListener(
topic = "ORDER_TOPIC",
selectorExpression = "CREATE",
consumerGroup = "stock-service-group"
)
@Slf4j
public class StockConsumer implements RocketMQListener<Order> {
@Autowired
private StockService stockService;
@Override
public void onMessage(Order order) {
// TCC Try:预占库存
boolean locked = stockService.tryLockStock(order.getOrderId(), order.getItems());
if (!locked) {
log.error("库存预占失败,orderId={}", order.getOrderId());
// 抛出异常触发重试,或发送补偿消息
throw new StockException("库存不足");
}
// 发送库存已锁定事件
stockService.publishStockLockedEvent(order);
}
}
4.2 案例:百万级日志实时处理
/**
* 高吞吐日志采集配置
*/
@Configuration
public class LogCollectorConfig {
@Bean
public DefaultMQProducer logProducer() throws MQClientException {
DefaultMQProducer producer = new DefaultMQProducer("log-producer-group");
producer.setNamesrvAddr("localhost:9876");
// 性能优化配置
producer.setDefaultTopicQueueNums(16); // 队列数
producer.setSendMsgTimeout(10000);
producer.setCompressMsgBodyOverHowmuch(4096);
producer.setRetryTimesWhenSendFailed(2);
// 批量发送配置
producer.setMaxMessageSize(4194304); // 4MB
producer.setSendLatencyFaultEnable(true); // 延迟故障转移
producer.start();
return producer;
}
/**
* 批量发送日志(每秒聚合发送)
*/
@Component
public class LogBatchSender {
private List<Message> buffer = new ArrayList<>();
private final int BATCH_SIZE = 100;
private final int FLUSH_INTERVAL = 1000; // ms
@Scheduled(fixedRate = FLUSH_INTERVAL)
public void flush() {
if (buffer.isEmpty()) return;
List<Message> batch = new ArrayList<>(buffer);
buffer.clear();
try {
producer.send(batch);
} catch (Exception e) {
// 降级:写入本地文件,定时重试
fallbackToLocal(batch);
}
}
public void send(LogEntry entry) {
Message msg = new Message("LOG_TOPIC", "APP_LOG",
JSON.toJSONBytes(entry));
synchronized (this) {
buffer.add(msg);
if (buffer.size() >= BATCH_SIZE) {
flush();
}
}
}
}
}
五、常见问题与排错指南
5.1 问题诊断流程图
┌─────────────────────────────────────────────────────────────┐
│ 消息发送失败 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 1. 检查 NameServer 连接 │
│ ├─ 网络是否连通:telnet nameserver 9876 │
│ ├─ 地址是否正确:检查 rocketmq.name-server 配置 │
│ └─ 防火墙是否放行 │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. 检查 Broker 状态 │
│ ├─ 查看集群列表:mqadmin clusterList -n localhost:9876 │
│ ├─ 查看Topic路由:mqadmin topicRoute -n localhost:9876 │
│ │ -t ORDER_TOPIC │
│ └─ 检查Broker日志:~/logs/rocketmqlogs/broker.log │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. 检查 Producer 配置 │
│ ├─ 生产者组是否重复 │
│ ├─ 消息大小是否超限(默认4MB) │
│ └─ 发送超时时间是否过短 │
└─────────────────────────────────────────────────────────────┘
5.2 高频问题速查表
问题一:No route info of this topic
现象:发送消息时抛出异常 "No route info for topic xxx"
原因分析:
├─ 1. Topic 未创建
├─ 2. Broker 未注册到 NameServer
├─ 3. Broker 权限问题(ACL)
└─ 4. 网络隔离
排查命令:
# 查看 Topic 是否存在
mqadmin topicList -n localhost:9876
# 查看 Topic 路由信息
mqadmin topicRoute -n localhost:9876 -t ORDER_TOPIC
# 创建 Topic(若不存在)
mqadmin updateTopic -n localhost:9876 -c DefaultCluster -t ORDER_TOPIC
解决方案:
1. 自动创建 Topic(开发环境):
broker.conf 中设置 autoCreateTopicEnable=true
2. 手动创建 Topic(生产环境):
mqadmin updateTopic -b localhost:10911 -t ORDER_TOPIC
3. 检查 Broker 注册:
查看 broker.log 中 "The broker[xxx] boot success" 日志
问题二:消息发送超时(RemotingTimeoutException)
现象:发送消息超时,异常信息包含 "sendDefaultImpl call timeout"
根因分析:
├─ 网络延迟高(跨机房部署)
├─ Broker 负载过高(磁盘IO瓶颈)
├─ 消息体过大(超过压缩阈值但未压缩)
└─ 发送并发度过高
优化方案:
1. 增加超时时间:
rocketmq.producer.send-message-timeout=10000
2. 启用消息压缩:
rocketmq.producer.compress-message-body-threshold=4096
3. 异步发送:
rocketMQTemplate.asyncSend(topic, message, sendCallback)
4. 批量发送:
rocketMQTemplate.syncSend(topic, messageList, timeout)
5. 开启故障转移:
producer.setSendLatencyFaultEnable(true);
问题三:消息消费堆积(Consumer Lag)
现象:消费延迟监控报警,消息堆积量持续增长
诊断步骤:
1. 查看消费进度:
mqadmin consumerProgress -n localhost:9876 -g consumer-group
2. 查看消费线程堆栈:
jstack -l <pid> | grep ConsumeMessageThread
3. 检查消费耗时:
查看 consumer.log 中 "consumeMessage cost" 日志
优化方案:
┌─────────────────────────────────────────────────────────────┐
│ 场景1:消费逻辑耗时过长 │
│ ├─ 优化业务逻辑(异步化、并行化) │
│ ├─ 增加消费线程数: │
│ │ consume-thread-min: 50 │
│ │ consume-thread-max: 200 │
│ └─ 扩容消费者实例(水平扩展) │
├─────────────────────────────────────────────────────────────┤
│ 场景2:消费异常导致频繁重试 │
│ ├─ 捕获异常,避免抛出到框架层 │
│ ├─ 设置重试策略: │
│ │ maxReconsumeTimes: 3 // 减少无效重试 │
│ └─ 死信队列处理: │
│ %DLQ%consumer-group 监控并告警 │
├─────────────────────────────────────────────────────────────┤
│ 场景3:网络瓶颈 │
│ ├─ 增加拉取批量大小:pullBatchSize: 64 │
│ └─ 启用压缩:consumer.setConsumeMessageBatchMaxSize(32) │
└─────────────────────────────────────────────────────────────┘
问题四:消息重复消费
现象:同一消息被消费多次,导致数据不一致
原因:
├─ 消费超时(默认15分钟)触发重试
├─ 消费异常返回 RECONSUME_LATER
├─ 消费者重启导致重新平衡
└─ 网络闪断导致确认丢失
幂等性解决方案:
1. 数据库唯一索引(推荐)
CREATE TABLE idempotent_log (
msg_key VARCHAR(64) PRIMARY KEY,
consume_time TIMESTAMP,
status VARCHAR(16)
);
2. Redis 分布式锁
@Component
public class IdempotentConsumer {
@Autowired
private StringRedisTemplate redisTemplate;
public void onMessage(Message message) {
String key = "msg:" + message.getKeys();
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(key, "1", 24, TimeUnit.HOURS);
if (!locked) {
log.warn("重复消息,跳过,key={}", key);
return; // 已消费过,直接返回
}
// 执行业务逻辑
processBusiness(message);
}
}
3. 业务状态机幂等
// 订单状态流转:CREATING -> CREATED -> PAID -> SHIPPED
// 同一状态多次处理结果一致
问题五:顺序消息消费乱序
现象:同一订单的消息未按发送顺序消费
原因分析:
├─ 并发消费模式(CONCURRENTLY)导致
├─ 队列数变更(扩容/缩容)
└─ 消费者重平衡触发
解决方案:
1. 使用顺序消费模式:
@RocketMQMessageListener(
consumeMode = ConsumeMode.ORDERLY, // 关键配置
consumeThreadMax = 1 // 单线程消费保证顺序
)
2. 正确的队列选择策略:
// 根据业务Key选择队列,保证同一业务Key进入同一队列
rocketMQTemplate.syncSendOrderly(
topic,
message,
order.getUserId() % 100 // 队列选择Key
);
3. 注意事项:
- 顺序消费性能较低(单线程)
- 某条消息阻塞会导致后续消息堆积
- 建议仅对必要场景使用(如订单状态流转)
5.3 生产环境排错命令集
# ========== 集群状态检查 ==========
# 1. 查看集群列表
mqadmin clusterList -n 192.168.1.100:9876
# 2. 查看Broker统计信息
mqadmin brokerStatus -n 192.168.1.100:9876 -b 192.168.1.101:10911
# 3. 查看NameServer配置
mqadmin getNamesrvConfig -n 192.168.1.100:9876
# ========== Topic 管理 ==========
# 4. 查看所有Topic
mqadmin topicList -n 192.168.1.100:9876
# 5. 查看Topic路由信息
mqadmin topicRoute -n 192.168.1.100:9876 -t ORDER_TOPIC
# 6. 查看Topic统计(消息量、TPS)
mqadmin topicStats -n 192.168.1.100:9876 -t ORDER_TOPIC
# 7. 查看Topic消费者组
mqadmin topicClusterList -n 192.168.1.100:9876 -t ORDER_TOPIC
# ========== 消费者诊断 ==========
# 8. 查看消费者组列表
mqadmin consumerProgress -n 192.168.1.100:9876 -g order-consumer-group
# 9. 查看消费者连接
mqadmin consumerConnection -n 192.168.1.100:9876 -g order-consumer-group
# 10. 查看消费进度(按队列)
mqadmin consumerProgress -n 192.168.1.100:9876 -g order-consumer-group -s true
# ========== 消息查询 ==========
# 11. 根据MsgId查询消息
mqadmin queryMsgById -n 192.168.1.100:9876 -i 0A0A0A0A0000000000000000000001
# 12. 根据Key查询消息
mqadmin queryMsgByKey -n 192.168.1.100:9876 -t ORDER_TOPIC -k ORDER_202403240001
# 13. 根据Offset查询消息
mqadmin queryMsgByOffset -n 192.168.1.100:9876 -b 192.168.1.101:10911 -i 0 -o 100
# ========== 消息重试与跳过 ==========
# 14. 查看死信队列消息
mqadmin printMsg -n 192.168.1.100:9876 -t %DLQ%order-consumer-group
# 15. 重置消费位点(紧急恢复)
mqadmin resetOffsetByTime -n 192.168.1.100:9876 -g order-consumer-group \
-t ORDER_TOPIC -s 2024-03-24#12:00:00:000
# ========== 性能分析 ==========
# 16. 查看Broker运行时配置
mqadmin getBrokerConfig -n 192.168.1.100:9876 -b 192.168.1.101:10911
# 17. 查看Broker存储统计
mqadmin brokerConsumeStats -n 192.168.1.100:9876 -b 192.168.1.101:10911
5.4 监控指标与告警
# Prometheus + Grafana 监控配置
rocketmq_broker_tps: # Broker 每秒处理消息数
threshold: > 10000
rocketmq_consumer_lag: # 消费延迟(消息数)
threshold: > 10000
rocketmq_consumer_latency: # 消费延迟(时间)
threshold: > 5m
rocketmq_broker_disk_usage: # 磁盘使用率
threshold: > 85%
rocketmq_broker_cpu_usage: # CPU使用率
threshold: > 80%
rocketmq_send_failure_rate: # 发送失败率
threshold: > 1%
rocketmq_consumer_failure_rate: # 消费失败率
threshold: > 5%
六、性能调优建议
6.1 生产者优化
| 优化项 | 配置参数 | 建议值 | 说明 |
|---|---|---|---|
| 发送方式 | sendMsgType |
ASYNC | 高吞吐场景使用异步 |
| 批量大小 | batchSize |
100-1000 | 根据消息大小调整 |
| 压缩阈值 | compressMsgBodyOverHowmuch |
4KB | 减少网络传输 |
| 故障转移 | sendLatencyFaultEnable |
true | 自动剔除慢节点 |
| 超时时间 | sendMsgTimeout |
3000ms | 避免过长等待 |
6.2 消费者优化
| 优化项 | 配置参数 | 建议值 | 说明 |
|---|---|---|---|
| 消费线程 | consumeThreadMin/Max |
20-64 | 根据CPU核数调整 |
| 拉取批量 | pullBatchSize |
32 | 平衡延迟与吞吐 |
| 消费批量 | consumeMessageBatchMaxSize |
1 | 顺序消费设为1 |
| 消费超时 | consumeTimeout |
15min | 防止无限重试 |
| 重试次数 | maxReconsumeTimes |
3-16 | 业务可容忍次数 |
6.3 Broker 配置优化
# broker.conf 生产环境推荐配置
# 存储路径(SSD推荐)
storePathRootDir=/data/rocketmq/store
storePathCommitLog=/data/rocketmq/store/commitlog
# 刷盘策略(SSD可用异步)
flushDiskType=ASYNC_FLUSH # 或 SYNC_FLUSH(金融场景)
# 主从复制(同步双写)
brokerRole=SYNC_MASTER # 或 ASYNC_MASTER / SLAVE
# 文件删除时间(磁盘充足可延长)
fileReservedTime=72 # 小时
deleteWhen=04 # 凌晨4点删除
# 内存配置(根据服务器调整)
sendMessageThreadPoolNums=16
pullMessageThreadPoolNums=16
queryMessageThreadPoolNums=8
# 开启长轮询
longPollingEnable=true
七、版本升级注意事项
7.1 4.x 升级到 5.x 关键变更
┌─────────────────────────────────────────────────────────────┐
│ RocketMQ 5.x 重大变更 │
├─────────────────────────────────────────────────────────────┤
│ 1. 架构变更:新增 Proxy 层,支持Grpc协议 │
│ ├─ 客户端连接改为连接 Proxy(端口8081) │
│ └─ 兼容4.x客户端(直连Broker) │
├─────────────────────────────────────────────────────────────┤
│ 2. 消费模式:新增 Pop 消费模式 │
│ ├─ 替代传统的 Push/Pull 模式 │
│ └─ 支持任意时间延迟消息(不再受限于18个级别) │
├─────────────────────────────────────────────────────────────┤
│ 3. 存储格式:CommitLog 格式变更 │
│ └─ 升级前必须全量消费完消息,或做数据迁移 │
├─────────────────────────────────────────────────────────────┤
│ 4. 配置变更:部分配置项名称调整 │
│ └─ 参考官方迁移指南:https://rocketmq.apache.org/... │
└─────────────────────────────────────────────────────────────┘
总结
RocketMQ 作为阿里巴巴开源的分布式消息中间件,在金融级可靠性、高吞吐量、丰富的消息特性等方面表现优异。通过本文的详细讲解,您应该掌握了:
- 核心原理:CommitLog + ConsumeQueue 存储架构、主从复制机制
- 版本选型:Spring Boot 2.7.x 搭配 RocketMQ 5.1.4 是当前稳定选择
- 实战开发:事务消息、顺序消息、延迟消息的具体实现
- 运维排错:完整的诊断流程和常用命令
建议在生产环境部署时,启用消息轨迹、配置完善的监控告警、制定消息堆积应急预案,以确保消息系统的稳定运行。