本地启动 NameServer 和 Broker | 读 RocketMQ 源码前的准备工作
- clone 并导入源码
 - 本地启动 NameServer
 - 本地启动 Broker
 - 本地运行生产者与消费者代码
 
完成上述步骤之后,RocketMQ的源码环境就搭建完毕了,之后就可以在本地启动以及收发消息,调试和分析RocketMQ的源码了。
clone 并导入源码
在 github 上选择对应的的代码 https://github.com/apache/rocketmq/tree/rocketmq-all-4.7.0,将其 clone 下来,再切出 4.7.0 版本的源码。Clone 到本地之后,用 IDEA 打开项目。

项目结构

| 模块 | 作用 | 
|---|---|
| broker | Broker 相关代码 | 
| client | Producer、Consumer 客户端代码,用于生产消息、消费消息 | 
| common | 公共代码 | 
| dev | 开发相关的信息 | 
| distribution | 部署相关,比如配置文件 | 
| example | 例子 | 
| filter | 过滤器 | 
| logappender | 日志相关 | 
| logging | 日志相关 | 
| namesvr | NameServer | 
| openmessaging | 开放消息标准 | 
| remoting | 远程网络通信,基于 netty 实现 | 
| srvutil | 工具类 | 
| store | 消息如何在 Broker 中进行存储相关代码 | 
| style | 代码检查 | 
| test | 测试 | 
| tools | 命令行监控 | 
本地启动 NameServer
接下来我们要做的是在本地启动 NameServer,包括两个步骤:
- 在 IDEA 中配置启动相关的信息,NameServer 的启动类是
org.apache.rocketmq.namesrv.NamesrvStartup - 准备好启动 NameServer 需要的配置文件和目录
 

看上图:
- 配置启动类的名字 
NameServerStartup - 配置主类的路径 
org.apache.rocketmq.namesrv.NamesrvStartup - 工作目录,也就是当前代码所在的目录
 - 运行目录 
ROCKETMQ_HOME,这个目录里面放的是运行时需要的配置文件、数据、日志等。你需要创建一个目录,在里面创建conf、logs、store目录 

接着将源码中 distrbution 模块中的 logback_namesvr.xml 文件拷贝到上面的 conf 目录下,并将这个文件中的${user.home}全部替换为前面配置的运行目录。

然后运行配置好的启动类,就会读取 conf 里的配置文件,并将日志打印在logs目录里,数据都会写在store目录里。看到 IDEA 的打印出下面这样的信息,就说明 NameServer 启动成功了。

本地运行 Broker
启动 Broker 和启动 NameServer 的过程类似。首先也是配置启动类:
- Broker 的启动类在 
org.apache.rocketmq.broker.BrokerStartup - 不一样的地方是要设置一个参数 
-c你的broker.conf配置文件的路径,因为程序启动的时候会读-c这个参数 - 接着还是设置工作目录和运行目录,选择 module 为 rocketmq-broker
 

接着把distrbution模块中的 broker.conf 和 logback_broker.xml 文件拷贝到 conf目录下:
- 将 logback_broker.xml 的
${user.home}替换为你的 RocketMQ 运行目录 - broker.conf 按照下面的配置方式进行配置
 
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
# nameserver的地址
namesrvAddr=127.0.0.1:9876
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
# 运行目录的store目录
storePathRootDir=/Users/shui/Desktop/rocketmq-nameserver/store
# commitLog的存储路径
storePathCommitLog=你的store目录/commitlog
# consume queue文件的存储路径
storePathConsumeQueue=你的store目录/consumequeue
# 消息索引文件的存储路径
storePathIndex=你的store目录/store/index
# checkpoint文件的存储路径
storeCheckpoint=你的store目录/checkpoint
# abort文件的存储路径
abortFile=你的store目录/abort
最后运行主类,看到控制台打印如下信息就表示启动成功:

此时 rocketmqlogs,里面有一个broker.log,就可以看到Broker的启动日志了:

本地运行生产者与消费者代码
在控制台创建一个 topic 名为 TopicTest。如果不知道如何使用 RocketMQ 的控制台,可以看我之前写这篇文章:https://www.cnblogs.com/shuiyj/p/13200658.html。

接着去修改 example 中给出的生产者和消费者代码 org.apache.rocketmq.example.quickstart.Consumer 和 org.apache.rocketmq.example.quickstart.Producer 。
生产者
改动两个地方:
- 设置 NameServer 地址,让生产者可以获取到 Broker 地址
 - 本来发送 1000 条信息,改少一点发送 3 条,便于消费的时候观察
 
public class Producer {
    public static void main(String[] args) throws MQClientException, InterruptedException {
        /*
         * Instantiate with a producer group name.
         */
        DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
        // 其他代码不变
      	// 在这里设置 NameServer 地址,保证  Producer 可以从 NameServer 获取到 Broker 地址
        producer.setNamesrvAddr("127.0.0.1:9876");
        /*
         * Launch the instance.
         */
        producer.start();
	     	
      // 本来是发送 1000 条消息,改成发送 3 条
        for (int i = 0; i < 3; i++) {
            try {
                /*
                 * Create a message instance, specifying topic, tag and message body.
                 */
                Message msg = new Message("TopicTest" /* Topic */,
                    "TagA" /* Tag */,
                    ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
                );
看到控制台输出如下所示的信息,表示消息发送成功了。
SendResult [sendStatus=SEND_OK, msgId=24098A28085A1DB0ECAD4CD655E7AF1548B818B4AAC28B1F132F0000, offsetMsgId=C0A8010800002A9F0000000000000000, messageQueue=MessageQueue [topic=TopicTest, brokerName=broker-a, queueId=2], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=24098A28085A1DB0ECAD4CD655E7AF1548B818B4AAC28B1F13AB0001, offsetMsgId=C0A8010800002A9F00000000000000CA, messageQueue=MessageQueue [topic=TopicTest, brokerName=broker-a, queueId=3], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=24098A28085A1DB0ECAD4CD655E7AF1548B818B4AAC28B1F13AE0002, offsetMsgId=C0A8010800002A9F0000000000000194, messageQueue=MessageQueue [topic=TopicTest, brokerName=broker-a, queueId=0], queueOffset=0]
消费者
消息者只改动一个地方,就是设置 NameServer 地址,也是为了获取到 Broker 的地址。
public class Consumer {
    public static void main(String[] args) throws InterruptedException, MQClientException {
        // 省略其它代码...
        // 设置 NameServer 地址,保证  Consumer 可以从 NameServer 获取到 Broker 地址
        consumer.setNamesrvAddr("127.0.0.1:9876");
        /*
         *  Launch the consumer instance.
         */
        consumer.start();
        System.out.printf("Consumer Started.%n");
    }
}
可以看到消费到了 3 条数据,并打印出了消息的相关信息。
00:24:23.571 [main] DEBUG i.n.u.i.l.InternalLoggerFactory - Using SLF4J as the default logging framework
Consumer Started.
ConsumeMessageThread_1 Receive New Messages: [MessageExt [brokerName=broker-a, queueId=3, storeSize=202, queueOffset=0, sysFlag=0, bornTimestamp=1593274869675, bornHost=/192.168.1.8:54010, storeTimestamp=1593274869676, storeHost=/192.168.1.8:10911, msgId=C0A8010800002A9F00000000000000CA, commitLogOffset=202, bodyCRC=1401636825, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=1, CONSUME_START_TIME=1593275064336, UNIQ_KEY=24098A28085A1DB0ECAD4CD655E7AF1548B818B4AAC28B1F13AB0001, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 49], transactionId='null'}]] 
ConsumeMessageThread_3 Receive New Messages: [MessageExt [brokerName=broker-a, queueId=0, storeSize=202, queueOffset=0, sysFlag=0, bornTimestamp=1593274869678, bornHost=/192.168.1.8:54010, storeTimestamp=1593274869679, storeHost=/192.168.1.8:10911, msgId=C0A8010800002A9F0000000000000194, commitLogOffset=404, bodyCRC=1250039395, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=1, CONSUME_START_TIME=1593275064339, UNIQ_KEY=24098A28085A1DB0ECAD4CD655E7AF1548B818B4AAC28B1F13AE0002, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 50], transactionId='null'}]] 
ConsumeMessageThread_2 Receive New Messages: [MessageExt [brokerName=broker-a, queueId=2, storeSize=202, queueOffset=0, sysFlag=0, bornTimestamp=1593274869552, bornHost=/192.168.1.8:54010, storeTimestamp=1593274869574, storeHost=/192.168.1.8:10911, msgId=C0A8010800002A9F0000000000000000, commitLogOffset=0, bodyCRC=613185359, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=1, CONSUME_START_TIME=1593275064340, UNIQ_KEY=24098A28085A1DB0ECAD4CD655E7AF1548B818B4AAC28B1F132F0000, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 48], transactionId='null'}]] 

                
            
        
浙公网安备 33010602011771号