RocketMQ从实战到源码:初识RocketMQ
😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 博客首页 @怒放吧德德 To记录领地 @一个有梦有戏的人
🌝分享学习心得,欢迎指正,大家一起学习成长!
转发请携带作者信息 @怒放吧德德(掘金) @一个有梦有戏的人(CSDN)

前言
接下来就是开启新一阶段的技术学习,要不断补充技能,于是我就开启了自己的 RocketMQ 技术,本次学习依旧是视频+AI+动手的方式进行学习,并持续产出文档。2025-12-30创建栏目,说要学习,一直出差,拖到现在!!!
1 RocketMQ 介绍
RocketMQ 是一个分布式、队列模型的开源消息中间件 ,由阿里巴巴团队最初开发,并于2016年捐赠给Apache软件基金会 ,2017年成为Apache顶级项目。它旨在处理海量消息的高吞吐、低延迟、高可用、高可靠的传输,是构建大型分布式系统的核心基础设施。
1.1 基本概念
- NameServer:可以看成是注册中心,负责更新和发现 Broker 服务,在 NameServer 集群中,NameServer 之间是没有相互通信的,它是无状态的。
- Broker:可以理解是消息中转角色,负责消息的存储与转化,接收生产者发送来的消息,并将其持久化到磁盘,根据消费者的拉取请求,将存储的消息投递出去;当用户发送消息到 Broker 时,Broker 会将消息转发到关联的 Topic 中。
1.1.1 核心组件与结构
- 主题(Topic):消息传输和存储的顶层容器,用于标识同一类业务逻辑的消息,通过 唯一标识。
- 消息队列(MessageQueue):消息存储和传输的实际容器,也是最小存储单元。主题由多个队列组成,通过 唯一标识。
- 消息(Message):最小数据传输单元,包含业务数据的负载和拓展属性。
- 消息视图(MessageView) :面向开发视角提供的一种消息只读接口,用于读取消息属性和负载信息,不能修改消息本身。
1.1.2 消息分类与属性
- 消息类型(MessageType) :按照消息传输特性定义的分类,包括:
- 普通消息
- 顺序消息
- 事务消息
- 定时/延时消息
- 从5.0版本开始,每个主题只允许发送一种消息类型,该强制校验功能默认开启。
- 消息标签(MessageTag):主题层级下细粒度的消息分类属性,消费者可订阅特定标签进行过滤。
- 消息索引(MessageKey):面向消息的索引属性,用于快速查找消息。
1.1.3 消息位置与进度
- 消息位点(MessageQueueOffset):消息在队列中的唯一 类型坐标,按到达服务端的顺序存储。
- 消费位点(ConsumerOffset) :每个消费者分组记录消费过的最新一条消息的位点。
- 重置消费位点:以时间轴为坐标,重新设置消费者分组对已订阅主题的消费进度。
1.1.4 生产者相关
- 生产者(Producer):构建并传输消息到服务端的运行实体,通常集成在业务系统中。
- 事务检查器(TransactionChecker):生产者用于执行本地事务检查和异常事务恢复的监听器。
- 事务状态(TransactionResolution) :事务消息发送过程中,事务提交的状态标识,包括:
- 事务提交
- 事务回滚
- 事务未决
1.1.5 消费者相关
- 消费者分组(ConsumerGroup) :承载多个消费行为一致的消费者的逻辑分组,用于实现负载均衡和高可用。
- 消费者(Consumer):接收并处理消息的运行实体。
- 消费结果(ConsumeResult) : 消费监听器返回的消息处理结果,包含消费成功 和消费失败。
- 订阅关系(Subscription):消费者获取和处理消息的规则与状态配置,包括过滤规则和消费进度维护。
1.1.6 高级功能与状态
- 消息过滤:消费者通过订阅指定消息标签(Tag)进行过滤,过滤计算在服务端完成。
- 消息轨迹:消息从生产到消费完整链路中各节点的时间、地点等数据,用于问题排查。
- 消息堆积:消息已发送到服务端,但因消费者消费能力有限,未能及时消费的状态。
- 事务消息:保障分布式场景下消息生产和本地事务最终一致性的高级消息类型。
- 定时/延时消息:发送至服务端后,在指定时间后才能被消费的高级消息类型。
- 顺序消息:支持消费者按照发送先后顺序获取和处理消息的高级消息类型。
1.2 RocketMQ 工作原理

官网介绍:
RocketMQ 5.0 引入了全新的弹性无状态代理模式,将当前的Broker职责进行拆分,对于客户端协议适配、权限管理、消费管理等计算逻辑进行抽离,独立无状态的代理角色提供服务,Broker则继续专注于存储能力的持续优化。这套模式可以更好地实现在云环境的资源弹性调度。 值得注意的是RocketMQ 5.0的全新模式是和4.0的极简架构模式相容相通的,5.0的代理架构完全可以以Local模式运行,实现与4.0架构完全一致的效果。开发者可以根据自身的业务场景自由选择架构部署。
2 安装 RocketMQ
2.1 下载 RocketMQ
本次使用的版本是 5.3.0
2.2 安装 RocketMQ
首先需要准备一台 centos 的虚拟机或服务器,并且需要安装 jdk,具体可以看看网上教程,这里不再赘述。
2.2.1上传安装包
通过使用 shell 工具将压缩包上传到虚拟机上:/usr/rocketmq ,我懒得在弄分类了,反正是虚拟机做测试,我就是直接上传解压。
shell
[root@localhost rocketmq]# cd /usr/rocketmq
# 如果想要管理可用以下命令
[root@localhost rocketmq]# mv rocketmq-all-5.3.0-bin-release /your/folder
[root@localhost rocketmq]# unzip rocketmq-all-5.3.0-bin-release.zip
[root@localhost rocketmq-all-5.3.0-bin-release]# ll
总用量 100
drwxr-xr-x. 2 root root 126 7月 10 2024 benchmark
drwxrwxr-x. 4 root root 4096 12月 30 00:03 bin
drwxr-xr-x. 8 root root 4096 7月 10 2024 conf
drwxr-xr-x. 2 root root 8192 7月 10 2024 lib
-rw-rw-r--. 1 root root 17327 7月 8 2024 LICENSE
-rw-------. 1 root root 44535 12月 28 13:24 nohup.out
-rw-rw-r--. 1 root root 1338 7月 8 2024 NOTICE
-rw-rw-r--. 1 root root 12266 7月 8 2024 README.md
bin:脚本目录,包含启动、停止和管理RocketMQ的各种脚本。
conf:配置文件目录,存放所有配置文件。
lib:依赖库目录,包含RocketMQ运行所需的所有JAR包,包括客户端、工具等 。
benchmark:性能测试工具
2.2.2 配置 RocketMQ 环境变量
shell
[root@localhost rocketmq]# vi /etc/profile
# 配置rocketmq路径
export ROCKETMQ_HOME=/usr/rocketmq/rocketmq-all-5.3.0-bin-release
2.2.3 更新配置
shell
[root@localhost rocketmq]# source /etc/profile
ROCKETMQ_HOME 的环境变量不配置的话,可能会在启动 NameServer 和 Broker 的时候报错。
2.2.4 启动服务
RocketMQ 需要启动两个,一个是 NameServer,另一个是 Broker。
① 启动 NameServer 服务
启动 NameServer 服务只需要在 rocketmq/bin 下有个吗 mqnamesrv。启动这个就行,但是其默认配置文件设置的 JVM 内存是 4G,这里我们需要修改,直接修改 runserver.sh
shell
[root@localhost rocketmq]# cd /usr/rocketmq/rocketmq-all-5.3.0-bin-release/bin
[root@localhost bin]# vi runserver.sh
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
改为
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
然后启动
shell
[root@localhost bin]# nohup ./mqnamesrv &
# 查看日志
[root@localhost bin]# tail -f nohup.out
显示 The Name Server boot success 就表示启动成功。
② 启动 Broker 服务
启动的脚本是 runbroker,但是这里默认配置内存是 8G,如果不够,需要调整一下 JVM 内存,修改 runbroker.sh 文件。
shell
[root@localhost rocketmq]# cd /usr/rocketmq/rocketmq-all-5.3.0-bin-release/bin
[root@localhost bin]# vi runbroker.sh
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"
改为
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m"
修改 broker 配置文件
shell
[root@localhost bin]# cd /usr/rocketmq/rocketmq-all-5.3.0-bin-release/conf
[root@localhost conf]# vi broker.conf
# 允许自动创建topic
autoCreateTopicEnable=true
# 添加nameserver地址
namesrvAddr=localhost:9876
启动 broker
shell
[root@localhost bin]# nohup ./mqbroker &
# 查看日志
[root@localhost bin]# tail -f nohup.out
[root@localhost bin]# jps
通过 jps 可以看到启动的 nameserve 和 broker 服务。
2.2.5 关闭服务
shell
sh ./mqshutdown broker
sh ./myshutdown namesrv
3 安装 rockermq-dashboard
安装 rocketmq 可视化界面,需要自行对代码进行编译打包,下载代码包,使用 idea 打开进行打包,这个过程不赘述。
3.1 运行可视化看板
将打包好的 jar 包放到虚拟机中,直接通过 java -jar 的方式进行运行即可。
shell
[root@localhost bin]# cd /usr/rocketmq
[root@localhost rocketmq]# java -jar rocketmq-dashboard-2.0.0.jar 1>dashboard.log 2>&1 &
启动完毕可以通过:http://192.168.109.134:8080/#/ 查看

(集群部署后续有时间补充...)
4 简单案例
可以参考源码里面的测试代码:rocketmq-example 模块下的 org.apache.rocketmq.example 包
需要先在 pom 引入坐标依赖
xml
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>5.1.0</version>
</dependency>
4.1 生产者
消息生产者的 3 种消息发送方法
- 同步方法:等待消息返回后再继续进行下面的操作。
- 异步方法:不等待消息返回直接进入后续流程,broker 将结果返回后调用 callback 函数,并使用 CountDownLatch 计数。
- 单向方法:只负责发送,不管消息是否发送成功。
① 同步发送
java
/**
* 同步发送
* @author: lyd
* @date: 2025/12/29 23:51
*/
public class SyncProducer {
public static final int MESSAGE_COUNT = 10;
public static final String PRODUCER_GROUP = "Test01";
public static final String DEFAULT_NAMESRVADDR = "192.168.109.134:9876";
public static final String TOPIC = "Topic-Lyd";
public static final String TAG = "Lyd";
public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, MQBrokerException, RemotingException, InterruptedException {
// 使用生产者组名进行实例化
DefaultMQProducer producer = new DefaultMQProducer(PRODUCER_GROUP);
producer.setNamesrvAddr(DEFAULT_NAMESRVADDR);
producer.start();
for (int i = 0; i < MESSAGE_COUNT; i++) {
Message msg = new Message(TOPIC,
TAG,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
);
// 调用发送消息以将消息传递到代理之一。
SendResult sendResult = producer.send(msg, 20 * 1000);
System.out.printf("发送成功%s%n", sendResult);
}
/*
* 当生产者实例不再使用时关闭。
*/
producer.shutdown();
}
}
如下就代表发送成功

② 异步发送
java
/**
* @author: lyd
* @date: 2025/12/30 00:09
*/
public class AsyncProducer {
public static final int MESSAGE_COUNT = 10;
public static final String PRODUCER_GROUP = "Test02";
public static final String DEFAULT_NAMESRVADDR = "192.168.109.134:9876";
public static final String TOPIC = "Topic-Lyd";
public static final String TAG = "Lyd";
public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, MQBrokerException, RemotingException, InterruptedException {
// 使用生产者组名进行实例化
DefaultMQProducer producer = new DefaultMQProducer(PRODUCER_GROUP);
producer.setNamesrvAddr(DEFAULT_NAMESRVADDR);
producer.start();
CountDownLatch countDownLatch = new CountDownLatch(MESSAGE_COUNT);
for (int i = 0; i < MESSAGE_COUNT; i++) {
Message msg = new Message(TOPIC,
TAG,
("异步发送:Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
);
// 调用发送消息以将消息传递到代理之一。
producer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
countDownLatch.countDown();
System.out.printf("异步发送成功%s%n", sendResult);
}
@Override
public void onException(Throwable throwable) {
countDownLatch.countDown();
System.out.printf("异步发送失败%s%n", throwable);
}
});
}
countDownLatch.await(5, TimeUnit.SECONDS);
/*
* 当生产者实例不再使用时关闭。
*/
producer.shutdown();
}
}
如下就表示成功

③ 单向发送
java
/**
* 单向发送
* @author: lyd
* @date: 2025/12/30 22:57
*/
public class OnewayProducer {
public static final int MESSAGE_COUNT = 10;
public static final String PRODUCER_GROUP = "Test03";
public static final String DEFAULT_NAMESRVADDR = "192.168.109.134:9876";
public static final String TOPIC = "Topic-Lyd";
public static final String TAG = "Lyd";
public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, MQBrokerException, RemotingException, InterruptedException {
// 使用生产者组名进行实例化
DefaultMQProducer producer = new DefaultMQProducer(PRODUCER_GROUP);
producer.setNamesrvAddr(DEFAULT_NAMESRVADDR);
producer.start();
for (int i = 0; i < MESSAGE_COUNT; i++) {
Message msg = new Message(TOPIC,
TAG,
("单发消息:Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
);
// 调用发送消息以将消息传递到代理之一。
producer.sendOneway(msg);
System.out.printf(i + "-发送成功");
}
Thread.sleep(5000);
/*
* 当生产者实例不再使用时关闭。
*/
producer.shutdown();
}
}
运行结果如下

4.2 消费者
消息的生产者分为两种:
- 拉模式:消费者主动到 broker 上去拉取。
- 推模式:消费者被动等待 broker 推送过来。
① 拉模式
如下代码,我们通过订阅"Topic-Lyd"主题,循环进行拉取,通过获取注册的 topic,在进行便利主题的消息队列,通过计算偏移量来主动获取消息,最后打印读取的消息并且将偏移量后移。
java
public class PullConsumer {
public static void main(String[] args) throws MQClientException {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("Test01");
consumer.setNamesrvAddr("192.168.109.134:9876");
Set<String> topics = new HashSet<>();
topics.add("Topic-Lyd");
consumer.setRegisterTopics(topics);
consumer.start();
// 循环拉取
while (true) {
consumer.getRegisterTopics().forEach(t -> {
try {
// 获取主题中的队列
Set<MessageQueue> messageQueues = consumer.fetchMessageQueuesInBalance(t);
messageQueues.forEach(query -> {
try {
// 获取query的偏移量
long offset = consumer.getOffsetStore().readOffset(query, ReadOffsetType.READ_FROM_MEMORY);
if (offset < 0) {
offset = consumer.getOffsetStore().readOffset(query, ReadOffsetType.READ_FROM_STORE);
}
if (offset < 0) {
offset = consumer.maxOffset(query);
}
if (offset < 0) {
offset = 0;
}
// 拉取query的消息,每次11条
PullResult pullResult = consumer.pull(query, "*", offset, 11);
// System.out.printf("循环拉取消息ing %s%n", pullResult);
switch (pullResult.getPullStatus()) {
case FOUND:
pullResult.getMsgFoundList().forEach(p -> {
System.out.println("消息拉取成功:" + p);
});
// 更新偏移量
consumer.updateConsumeOffset(query, pullResult.getNextBeginOffset());
}
} catch (MQClientException e) {
throw new RuntimeException(e);
} catch (MQBrokerException e) {
throw new RuntimeException(e);
} catch (RemotingException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
} catch (MQClientException e) {
throw new RuntimeException(e);
}
});
}
}
}
当我启动一个生产者推送数据的时候,这里就能看到拉取成功

② 推模式
以下例子是通过设置消息监听器:MessageListenerConcurrently 进行获取得到消息并进行消费。
java
public class PushConsumer {
public static void main(String[] args) throws MQClientException {
// 创建默认的推模式消费者实例,消费者组名为"Test01"
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("Test01");
// 设置NameServer地址,用于连接RocketMQ集群
consumer.setNamesrvAddr("192.168.109.134:9876");
// 订阅主题"Topic-Lyd","*"表示订阅所有标签的消息
consumer.subscribe("Topic-Lyd", "*");
// 设置消息监听器,处理接收到的消息
consumer.setMessageListener((MessageListenerConcurrently) (list, consumeConcurrentlyContext) -> {
// 遍历消息列表并打印每条消息
list.forEach(m -> {
System.out.println("收到消息:" + m);
});
// 返回消费成功状态
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
// 启动消费者
consumer.start();
System.out.println("消费者已启动!");
}
}
5 总结
RocketMQ 就是一个高性能的消息中转站,让系统之间解耦、异步、可靠地通信。安装时注意改内存,使用时先启动 NameServer 和 Broker,然后按需选择收发方式即可。本文介绍了什么 RocketMQ 以及单机安装和简单的案例,对于集群部署,因为这篇文章是我弄完之后的产出,集群部署要截图的比较多,后续在重新整理。
转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人
持续创作很不容易,作者将以尽可能的详细把所学知识分享各位开发者,一起进步一起学习。转载请携带链接,转载到微信公众号请勿选择原创,谢谢!
👍创作不易,如有错误请指正,感谢观看!记得点赞哦!👍
谢谢支持!