引言:从“拥有地图”到“打造工具”
在前两篇文章中我们确立了此行的目标与“读码心法”,然后绘制了一幅清晰的RocketMQ宏观架构“藏宝图”,认识了四大核心角色。可以说,我们现在“心中有数,眼中有图”。
然而,河水到底多深,还是要自己下脚去试试才能有更深刻的感受。在真正深入那片蕴藏着无尽宝藏的源码森林之前,我们还缺一件最关键的东西——一套属于我们自己的、精良的“探索工具”。
这套工具,就是我们今天要亲手搭建的。一个可以随时单步调试、任意修改、反复运行的本地源码环境,对于我们理解一个复杂系统而言,其价值是任何文档都无法替代的。它能让我们:
-
将抽象的流程具象化:当理论让困惑时,逐行的调试,亲眼看看代码是如何执行的,所有疑惑都将烟消云散。
-
无畏地进行实验:想知道如果某个参数改了会怎样?想验证一段逻辑在异常情况下如何处理?在本地实验室里,可以尽情“破坏”,而无需担心任何线上风险。
-
成为系统的主人:当能随心所欲地驾驭和观察它的每一个细节时,它在眼中就不再是一个神秘的黑盒,而是完全掌控的“白盒”。
因此,本文将是一次纯粹的、手把手的动手实践。我们将分为两个部分:
-
第一部分:搭建“源码实验室”。我们将从零开始,一步步地克隆、编译、配置并成功在IDE中运行一个本地的RocketMQ集群。
-
第二部分:消息的“诞生”。我们将编写第一个Producer,成功发送一条消息,通过Debug,亲眼见证这条消息“诞生”的瞬间,找到其真正起点。
一、 搭建“源码实验室”
1. 准备环境
在开始之前,请确保已经安装了以下工具:
-
Git:用于从代码仓库克隆源码。
-
JDK:RocketMQ基于Java开发,最好确保的JDK版本不低于1.8。
-
Maven 3.5+:用于项目的构建和依赖管理。
-
IntelliJ IDEA:强烈推荐使用IDEA,其强大的Debug和代码分析功能,是我们此行的“瑞士军刀”。(当然,Eclipse用户也可以参照类似步骤进行)。
2. 第一步:克隆源码与本地构建
a. 克隆源码:打开的命令行工具,执行以下命令,从Apache的官方GitHub仓库克隆最新的RocketMQ源码。
git clone https://github.com/apache/rocketmq.git
建议: 如果GitHub访问速度较慢,可以使用其中文官方网站(https://rocketmq.apache.org/zh/download)下载压缩包。
b. 切换到稳定版本:为了保证学习的稳定性,我们不直接使用主分支的开发代码,而是切换到一个相对稳定的release版本,例如 release-4.9.0。如果是下载压缩包,那就直接选择这个4.9.0版本下载即可。
cd rocketmq
git checkout release-4.9.0
c. 使用Maven构建:在rocketmq根目录下,执行Maven构建命令。
mvn clean install -DskipTests
-DskipTests参数会跳过单元测试,可以大幅加快构建速度。当在控制台看到[INFO] BUILD SUCCESS时,恭喜,RocketMQ的“零件”已经被我们成功生产出来了。
3. 第二步:在IDEA中配置并启动“指挥中心”—— NameServer
现在,我们要在IDEA中,把这些“零件”组装成一个能运行的系统。首先启动NameServer。
-
导入项目:在IDEA中,选择
File -> Open,找到刚才的rocketmq文件夹,将其作为Maven项目导入。等待IDEA索引完成。 -
找到启动类:在项目结构中,导航到
namesrv模块,找到启动类:org.apache.rocketmq.namesrv.NamesrvStartup.java。

-
配置环境变量(关键步骤):在启动前,RocketMQ需要知道它的“家”在哪里,以便存放日志等文件。我们需要配置一个
ROCKETMQ_HOME环境变量。-
在IDEA中,点击
Run -> Edit Configurations...。 -
点击左上角的
+号,选择Application。 -
Name:
NameServer -
Main class: 选择我们刚才找到的
NamesrvStartup。 -
Environment variables: 点击旁边的按钮,添加一个环境变量,
Name:ROCKETMQ_HOME,Value: 可以指定一个电脑上的目录,例如/Users/yourname/rocketmq_home。 -
点击
OK保存。
-
-
启动:现在,可以直接运行刚才创建的
NameServer配置。当在控制台看到类似The Name Server boot success...的日志时,我们的“调度指挥中心”就已经开始工作了!
4. 第三步:启动“心脏中枢”—— Broker
NameServer启动后,它只是一个空壳的指挥部,没有任何“士兵”向它报到。现在,我们来启动核心的Broker。
-
找到启动类:导航到
broker模块,找到启动类:org.apache.rocketmq.broker.BrokerStartup。 -
创建配置文件(关键步骤):Broker的配置比NameServer复杂,我们需要一个配置文件来告诉它NameServer的地址、自己是谁等信息。
-
在
rocketmq源码的distribution/conf目录下,会找到很多配置文件模板。我们选择broker.conf。 -
复制一份
broker.conf到刚才创建的ROCKETMQ_HOME目录下(例如/Users/yourname/rocketmq_home/conf/broker.conf)。 -
修改这份新的
broker.conf文件,确保以下配置是正确的:
-
# broker名字,master节点必须是broker-a
brokerName = broker-a
# Master Broker的ID,0表示是Master
brokerId = 0
# NameServer地址,指向我们本地启动的NameServer
namesrvAddr = 127.0.0.1:9876
# CommitLog存储路径
storePathRootDir = /Users/yourname/rocketmq_home/store
# ConsumeQueue存储路径
storePathConsumeQueue = /Users/yourname/rocketmq_home/store/consumequeue
# 消息索引存储路径
storePathIndex = /Users/yourname/rocketmq_home/store/index
# checkpoint文件路径
storeCheckpoint = /Users/yourname/rocketmq_home/store/checkpoint
# abort文件路径
abortFile = /Users/yourname/rocketmq_home/store/abort
请务必将路径替换为自己电脑的实际路径。
-
配置并启动Broker:
-
和NameServer一样,创建一个新的
Application运行配置。 -
Name:
Broker -
Main class:
BrokerStartup -
Program arguments:
-c /Users/yourname/rocketmq_home/conf/broker.conf(这里的-c参数,就是告诉Broker去哪里加载配置文件)。 -
Environment variables: 同样需要配置
ROCKETMQ_HOME。 -
点击
OK保存。
-
-
启动:运行
Broker配置。观察NameServer的控制台,会看到Broker前来“报到”的日志。同时,Broker自己的控制台也会显示The broker[broker-a, x.x.x.x:10911] boot success...。
至此,恭喜!一个功能完整的、本地的、随时可以被我们“随便玩”的RocketMQ核心集群,已经成功运行起来了!我们的“源码实验室”搭建完成!
二、 消息的“诞生”
实验室已经就绪,现在,向这个系统发送第一条消息,并通过Debug,找到这条消息生命周期的入口。
1. 编写我们的第一个“发件人”—— Producer
在的项目中,创建一个新的Maven模块(例如rocketmq-example),并引入rocketmq-client依赖。然后,编写以下代码:
package com.architect.mq.demo
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import java.nio.charset.StandardCharsets;
/**
@author yuda
测试producer发消息
*/
public class MyProducer {
public static void main(String[] args) throws Exception {
// 1. 创建一个Producer,指定一个Group Name
DefaultMQProducer producer = new DefaultMQProducer("MY_PRODUCER_GROUP");
// 2. 指定NameServer的地址
producer.setNamesrvAddr("127.0.0.1:9876");
// 3. 启动Producer
producer.start();
System.out.println("Producer Started.");
// 4. 创建一条消息
// Topic: 我们消息要发往的topic
// Body: 消息的内容
Message msg = new Message("MY_TOPIC",
"Hello RocketMQ!".getBytes(StandardCharsets.UTF_8));
// 5. 发送消息
System.out.println("Sending message...");
SendResult sendResult = producer.send(msg);
// 6. 打印发送结果
System.out.printf("Message Sent Successfully: %s%n", sendResult);
// 7. 关闭Producer
producer.shutdown();
System.out.println("Producer Shutdown.");
}
}
2. 见证奇迹的时刻
直接运行MyProducer的main方法。如果一切顺利,将在控制台看到类似的打印内容:
Producer Started.
Sending message...
Message Sent Successfully: SendResult [sendStatus=SEND_OK, msgId=..., offsetMsgId=..., messageQueue=..., queueOffset=...]
Producer Shutdown.
当看到SEND_OK时,请给自己一点掌声!已经完成了与这个复杂分布式系统的第一次成功交互。发送的消息,此刻已经存储在Broker的磁盘上。
3. 找到入口:设置我们的第一个断点

发送成功只是第一步,我们的目标是“偷师”。现在,让我们找到消息“诞生”的真正起点。
-
进入
producer.send(msg)方法,进入到DefaultMQProducer类中的send()方法。 -
会看到它内部调用了
this.defaultMQProducerImpl.send(msg)。继续跟进去,将来到DefaultMQProducerImpl类。 -
在这个类里,会看到一个核心的发送方法
sendDefaultImpl(...)。这就是我们要找的入口! -
在这个方法的第一行,打上一个断点
现在,以Debug模式,重新运行MyProducer。程序将会在设置的断点处停下来。
通过观察调用栈,可以清晰地看到main方法是如何一步步调用,最终走到这里的。观察变量,可以看到我们创建的Message对象,以及producer实例内部的所有状态。
这个断点,就是我们下一篇文章,深入探索Producer内部世界的“起点”。
结语:从“旁观者”到“参与者”
今天,我们没有深入任何一行复杂的源码,但通过亲手搭建起这个“源码实验室”,我们已经成功地将自己的角色,从一个RocketMQ的“旁观者”,转变为一个可以随时介入、观察、甚至改变其行为的“参与者”。
我们成功地启动了核心集群,发送了第一条消息,并且精准地找到了探索消息发送之旅的入口——sendDefaultImpl方法。
从下一篇文章开始,我们将从这个断点出发,正式踏入消息的内部世界,去探寻它在发送过程中,是如何找到正确的Broker(路由与负载均衡),以及Broker又是如何用何种方式,将我们的消息写入磁盘,创造出惊人的性能奇迹。
1万+

被折叠的 条评论
为什么被折叠?



