CentOS-7环境
rocketmq4.9.5
一、搭建rocketmq单机服务
官网地址:RocketMQ · 官方网站 | RocketMQ
我的理解:rocketmq搭建需要开启两个Java程序,所以就需要jdk环境,一个是nameserver服务,用于注册broker的元数据信息,另一个broker服务用于实际存储消息;生产者通过nameserver找到broker地址,broker再把消息推送给消费者
1、jdk环境的安装(rocketmq运行需要)
通过网盘分享的文件:jdk-8u161-linux-x64.tar.gz
链接: https://pan.baidu.com/s/1zrIas_-xzj8ZXkscJBSvfQ 提取码: yac1
1)解压
bash
tar -zxvf jdk-8u161-linux-x64.tar.gz
2)配置环境变量
打开用户级环境变量配置文件,也可以打开系统级的环境变量配置文件/etc/profile,是一样
bash
vim ~/.bash_profile
# 如果进入文件想要查看文件行号 输入如下
:set nu
追加如下内容
bash
export JAVA_HOME=/app/jdk/jdk1.8.0_161
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
执行配置生效命令
bash
source ~/.bash_profile
3)验证安装
bash
java -version

2、maven环境的安装
这个后面用于rocketmq可视化界面的源码打成jar包
下载地址:Download Apache Maven -- Maven
1)解压
tar -zxvf apache-maven-3.9.9-bin.tar.gz
2)配置环境变量
bash
vim ~/.bash_profile
# 如果进入文件想要查看文件行号 输入如下
:set nu
追加如下内容
bash
export MAVEN_HOME=/app/maven/apache-maven-3.9.9
export PATH=$MAVEN_HOME/bin:$PATH
执行配置生效命令
bash
source ~/.bash_profile
3)配置阿里云镜像
bash
vim settings.xml
bash
<mirror>
<id>alimaven</id>
<mirrorOf>*</mirrorOf>
<name>Aliyun Global Maven</name>
<url>https://maven.aliyun.com/repository/public/</url>
</mirror>
<localRepository>/path/to/local/repo</localRepository>也需要指定一下
4)验证安装
bash
mvn -v
3、rocketmq单机搭建
rocketmq下载地址:下载 | RocketMQ
RocketMQ建议的运行环境需要至少12G的内存,这是生产环境比较理想的资源配置
1)配置NameServer的jvm参数
bash
# 切换到rocketmq的bin目录下打开runserver.sh文件
vim runserver.sh

bash
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
2)配置Broker的jvm参数
bash
# 切换到rocketmq的bin目录下打开runbroker.sh文件
vim runbroker.sh

bash
JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"
修改为:
JAVA_OPT="${JAVA_OPT} -server -Xms1g -Xmx1g"
3)启动
1】启动nameserver服务
bash
# 切换到rocketmq的home目录下,启动nameserver服务
nohup bin/mqnamesrv &
2】启动broker服务
bash
# 切换到rocketmq的conf目录,修改broker.conf文件
vim broker.conf
# 追加如下行(如果生产者尝试向一个不存在的主题发送消息,消息系统会自动创建这个主题,而不需要管理员事先手动创建)
autoCreateTopicEnable=true
bash
# 切换到rocketmq的home目录下,启动broker服务
nohup bin/mqbroker &
如果服务器有多张网卡, 就需要配置brokerIP1=外网ip,这样才能通过这个ip访问到服务器上的rocketmq服务
注:1、在实际服务部署时,通常会将RocketMQ的部署地址添加到环境变量当中。例如使用vi ~/.bash_profile指令,添加以下内容。export ROCKETMQ_HOME=/app/rocketmq/rocketmq-all-4.9.5-bin-releasePATH=ROCKETMQ_HOME/bin:PATHexport PATH
这样就不必每次进入RocketMQ的安装目录了。直接可以使用mqnamesrv 和mqbroker指令。
2、停止RocketMQ服务可以通过mqshutdown指令进行
bin/mqshutdown namesrv # 关闭nameserver服务
bin/mqshutdown broker # 关闭broker服务
通过jps指令查看服务启动状态
二、快速实现消息收发
1、通过命令实现消息收发
1)指定nameserver地址
bash
vi ~/.bash_profile
追加如下内容
bash
export NAMESRV_ADDR='localhost:9876'
执行配置生效命令
bash
source ~/.bash_profile
2)生产者发送消息
bash
# 切换到rocketmq的home目录下执行(默认往RocketMQ中发送1000条消息)
bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

3)消费者接收消息
bash
# 切换到rocketmq的home目录下执行
bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

2、搭建maven项目实现消息收发
1)引入maven依赖
XML
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.5</version>
</dependency>
2)生产者客户端代码
java
public class Producer {
public static void main(String[] args) throws MQClientException, InterruptedException {
//初始化一个消息生产者
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
// 指定nameserver地址
producer.setNamesrvAddr("192.168.225.134:9876");
// 启动消息生产者服务
producer.start();
for (int i = 0; i < 2; i++) {
try {
// 创建消息。消息由Topic,Tag和body三个属性组成,其中Body就是消息内容
Message msg = new Message("TopicTest","TagA",("Hello RocketMQ " +i).getBytes(RemotingHelper.DEFAULT_CHARSET));
//发送消息,获取发送结果
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
} catch (Exception e) {
e.printStackTrace();
Thread.sleep(1000);
}
}
//消息发送完后,停止消息生产者服务。
producer.shutdown();
}
}
3)消费者客户端代码
java
public class Consumer {
public static void main(String[] args) throws InterruptedException, MQClientException {
//构建一个消息消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");
//指定nameserver地址
consumer.setNamesrvAddr("192.168.225.134:9876");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
// 订阅一个感兴趣的话题,这个话题需要与消息的topic一致
consumer.subscribe("TopicTest", "*");
// 注册一个消息回调函数,消费到消息后就会触发回调。
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,ConsumeConcurrentlyContext context) {
msgs.forEach(messageExt -> {
try {
System.out.println("收到消息:"+new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET));
} catch (UnsupportedEncodingException e) {}
});
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//启动消费者服务
consumer.start();
System.out.print("Consumer Started");
}
}
三、搭建rocketmq可视化界面
rocketmq下载地址:下载 | RocketMQ,在最下面找dashboard

1、编译
把源码包下载后,解压之后,切换到rocketmq-dashboard-2.0.0-source-release项目目录下,执行如下命令
java
mvn clean package -Dmaven.test.skip=true
在rocketmq-dashboard-2.0.0-source-release项目目录下生成target/rocketmq-dashboard-2.0.0.jar文件

2、运行
在jar文件所在目录新建application.yml指定nameserver地址,内容如下
java
rocketmq:
config:
namesrvAddrs:
- 192.168.225.134:9876
接下来执行如下命令
java
java -jar rocketmq-dashboard-2.0.0.jar
3、管理界面
运行后访问http://192.168.225.134:8080/

四、分布式集群搭建
集群结构图(两主两从异步)

配置主机/etc/hosts如下
bash
cat /etc/hosts
192.168.225.134 worker-rocketmq1
192.168.225.135 worker-rocketmq2
192.168.225.136 worker-rocketmq3
1、配置nameserver
nameserver不需要做特别的配置,worker-rocketmq1已经配置了,只需要配置另外两台就行了
1)新建目录
在worker-rocketmq2和worker-rocketmq3执行如下命令
mkdir -p /app/rocketmq
mkdir -p /app/jdk
2)复制文件
在worker-rocketmq1执行如下命令,把文件复制到worker-rocketmq2和worker-rocketmq3上
bash
#在/app/rocket目录下执行
scp -r rocketmq-all-4.9.5-bin-release root@worker-rocketmq2:/app/rocketmq
scp -r /app/jdk/jdk1.8.0_161/ root@worker-rocketmq2:/app/jdk
scp -r rocketmq-all-4.9.5-bin-release root@worker-rocketmq3:/app/rocketmq
scp -r /app/jdk/jdk1.8.0_161/ root@worker-rocketmq3:/app/jdk
3)配置
jdk配置
bash
vim ~/.bash_profile
export JAVA_HOME=/app/jdk/jdk1.8.0_161
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
source ~/.bash_profile
nameserver的jvm参数之前改过了,所以就这样
2、配置broker
1)broker-a配置
在worker-rocketmq1执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/2m-2s-async/broker-a.properties
配置如下
bash
#所属集群名字,名字一样的节点就在同一个集群内
brokerClusterName=rocketmq-cluster
#broker名字,名字一样的节点就是一组主从节点。
brokerName=broker-a
#brokerid,0就表示是Master,>0的都是表示 Slave
brokerId=0
#nameServer地址,分号分割
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
deleteWhen=04
fileReservedTime=120
#存储路径
storePathRootDir=/app/rocketmq/store
storePathCommitLog=/app/rocketmq/store/commitlog
storePathConsumeQueue=/app/rocketmq/store/consumequeue
storePathIndex=/app/rocketmq/store/index
storeCheckpoint=/app/rocketmq/store/checkpoint
abortFile=/app/rocketmq/store/abort
#Broker 的角色
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
#Broker 对外服务的监听端口
listenPort=10911
2)broker-a-s配置
在worker-rocketmq2执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/2m-2s-async/broker-a-s.properties
配置如下
bash
#所属集群名字,名字一样的节点就在同一个集群内
brokerClusterName=rocketmq-cluster
#broker名字,名字一样的节点就是一组主从节点。
brokerName=broker-a
#brokerid,0就表示是Master,>0的都是表示 Slave
brokerId=1
#nameServer地址,分号分割
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
deleteWhen=04
fileReservedTime=120
#存储路径
storePathRootDir=/app/rocketmq/storeSlave
storePathCommitLog=/app/rocketmq/storeSlave/commitlog
storePathConsumeQueue=/app/rocketmq/storeSlave/consumequeue
storePathIndex=/app/rocketmq/storeSlave/index
storeCheckpoint=/app/rocketmq/storeSlave/checkpoint
abortFile=/app/rocketmq/storeSlave/abort
#Broker 的角色
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
#Broker 对外服务的监听端口
listenPort=11011
3)broker-b配置
在worker-rocketmq2执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/2m-2s-async/broker-b.properties
配置如下
bash
#所属集群名字,名字一样的节点就在同一个集群内
brokerClusterName=rocketmq-cluster
#broker名字,名字一样的节点就是一组主从节点。
brokerName=broker-b
#brokerid,0就表示是Master,>0的都是表示 Slave
brokerId=0
#nameServer地址,分号分割
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
deleteWhen=04
fileReservedTime=120
#存储路径
storePathRootDir=/app/rocketmq/store
storePathCommitLog=/app/rocketmq/store/commitlog
storePathConsumeQueue=/app/rocketmq/store/consumequeue
storePathIndex=/app/rocketmq/store/index
storeCheckpoint=/app/rocketmq/store/checkpoint
abortFile=/app/rocketmq/store/abort
#Broker 的角色
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
#Broker 对外服务的监听端口
listenPort=10911
4)broker-b-s配置
在worker-rocketmq1执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/2m-2s-async/broker-b-s.properties
配置如下
bash
#所属集群名字,名字一样的节点就在同一个集群内
brokerClusterName=rocketmq-cluster
#broker名字,名字一样的节点就是一组主从节点。
brokerName=broker-b
#brokerid,0就表示是Master,>0的都是表示 Slave
brokerId=1
#nameServer地址,分号分割
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
deleteWhen=04
fileReservedTime=120
#存储路径
storePathRootDir=/app/rocketmq/storeSlave
storePathCommitLog=/app/rocketmq/storeSlave/commitlog
storePathConsumeQueue=/app/rocketmq/storeSlave/consumequeue
storePathIndex=/app/rocketmq/storeSlave/index
storeCheckpoint=/app/rocketmq/storeSlave/checkpoint
abortFile=/app/rocketmq/storeSlave/abort
#Broker 的角色
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
#Broker 对外服务的监听端口
listenPort=11011
这样就完成了2主2从集群的配置。配置过程汇总有几个需要注意的配置项:
-
store开头的一系列配置:表示RocketMQ的存盘文件地址。在同一个机器上需要部署多个Broker服务时,不同服务的存储目录不能相同。
-
listenPort:表示Broker对外提供服务的端口。这个端口默认是10911。在同一个机器上部署多个Broker服务时,不同服务占用的端口也不能相同。
-
如果你使用的是多网卡的服务器,比如阿里云上的云服务器,那么就需要在配置文件中增加配置一个brokerIP1属性,指向所在机器的外网网卡地址。
3、启动nameserver
worker-rocketmq1、worker-rocketmq2、worker-rocketmq3都执行如下命令
bash
# 切换到rocketmq的home目录下,启动nameserver服务
nohup bin/mqnamesrv &
4、启动broker
worker-rocketmq1启动broker-a和broker-b-s
bash
# 切换到rocketmq的home目录下
nohup bin/mqbroker -c ./conf/2m-2s-async/broker-a.properties &
nohup bin/mqbroker -c ./conf/2m-2s-async/broker-b-s.properties &
worker-rocketmq2启动broker-b和broker-a-s
bash
nohup bin/mqbroker -c ./conf/2m-2s-async/broker-b.properties &
nohup bin/mqbroker -c ./conf/2m-2s-async/broker-a-s.properties &
5、检查集群服务状态
bash
#切换到rocketmq的home目录下(需要配置NAMESRV环境变量)
bin/mqadmin clusterList

之前的dashboard可视化界面,application.yml重新指定nameserver地址
bash
rocketmq:
config:
namesrvAddrs:
- worker-rocketmq1:9876
- worker-rocketmq2:9876
- worker-rocketmq3:9876
运行后运行情况

五、高可用集群搭建
上面集群不会自动主从切换(优点就是服务宕机消息不会丢失),而rocketmq还有一种Dledger集群基于Raft协议(多数选举出主节点),可以实现主从自动切换,意味着集群中必须要超过半数以上节点正常运行集群才能正常工作(我觉得大概知道怎么回事就行了,再研究Dledger集群原理没多大意义)
注:在RocketMQ运行包的bin/dledger目录下,RocketMQ还提供了一个fast-try.sh脚本。这个脚本会指定conf/deldger目录下的配置文件,直接启动有三个broker服务的Dledger集群。每个集群指定的内存大小占用1G。
在conf/dledger目录下,RocketMQ默认给出了三个配置文件,这三个配置文件可以在单机情况下直接部署成一个具有三个broker服务的Dledger集群,我们只需要按照这个配置进行修改即可。

1、nameserver配置
搭建过的nameserver不用动了
2、broker配置
在三台机器的conf/dledger目录下,都创建一个broker.conf文件
1)worker-rocketmq1配置
执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/dledger/broker.conf
配置如下
bash
brokerClusterName = RaftCluster
brokerName=RaftNode00
listenPort=30911
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
storePathRootDir=/app/rocketmq/storeDledger/
storePathCommitLog=/app/rocketmq/storeDledger/commitlog
storePathConsumeQueue=/app/rocketmq/storeDledger/consumequeue
storePathIndex=/app/rocketmq/storeDledger/index
storeCheckpoint=/app/rocketmq/storeDledger/checkpoint
abortFile=/app/rocketmq/storeDledger/abort
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-worker-rocketmq1:40911;n1-worker-rocketmq2:40911;n2-worker-rocketmq3:40911
## must be unique
dLegerSelfId=n0
sendMessageThreadPoolNums=16
2)worker-rocketmq2配置
执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/dledger/broker.conf
配置如下
bash
brokerClusterName = RaftCluster
brokerName=RaftNode00
listenPort=30911
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
storePathRootDir=/app/rocketmq/storeDledger/
storePathCommitLog=/app/rocketmq/storeDledger/commitlog
storePathConsumeQueue=/app/rocketmq/storeDledger/consumequeue
storePathIndex=/app/rocketmq/storeDledger/index
storeCheckpoint=/app/rocketmq/storeDledger/checkpoint
abortFile=/app/rocketmq/storeDledger/abort
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-worker-rocketmq1:40911;n1-worker-rocketmq2:40911;n2-worker-rocketmq3:40911
## must be unique
dLegerSelfId=n1
sendMessageThreadPoolNums=16
3)worker-rocketmq3配置
执行如下命令
bash
vim /app/rocketmq/rocketmq-all-4.9.5-bin-release/conf/dledger/broker.conf
配置如下
bash
brokerClusterName = RaftCluster
brokerName=RaftNode00
listenPort=30911
namesrvAddr=worker-rocketmq1:9876;worker-rocketmq2:9876;worker-rocketmq3:9876
storePathRootDir=/app/rocketmq/storeDledger/
storePathCommitLog=/app/rocketmq/storeDledger/commitlog
storePathConsumeQueue=/app/rocketmq/storeDledger/consumequeue
storePathIndex=/app/rocketmq/storeDledger/index
storeCheckpoint=/app/rocketmq/storeDledger/checkpoint
abortFile=/app/rocketmq/storeDledger/abort
enableDLegerCommitLog=true
dLegerGroup=RaftNode00
dLegerPeers=n0-worker-rocketmq1:40911;n1-worker-rocketmq2:40911;n2-worker-rocketmq3:40911
## must be unique
dLegerSelfId=n2
sendMessageThreadPoolNums=16
这里对几个需要重点关注的配置项,做下介绍:
-
enableDLegerCommitLog: 是否启动Dledger。true表示启动
-
namesrvAddr: 指定nameserver地址
-
dLedgerGroup: Dledger Raft Group的名字,建议跟brokerName保持一致。
-
dLedgerPeers: Dledger Group内各个服务节点的地址及端口信息。同一个Group内的各个节点配置必须要保持一致。
-
dLedgerSelfId: Dledger节点ID,必须属于dLedgerPeers中的一个。同一个Group内的各个节点必须不能重复。
-
sendMessageThreadPoolNums:dLedger内部发送消息的线程数,建议配置成cpu核心数。
-
store开头的一系列配置: 这些是配置dLedger集群的消息存盘目录。如果你是从主从架构升级成为dLedger架构,那么这个地址可以指向之前搭建住主从架构的地址。dLedger集群会兼容主从架构集群的消息格式,只不过主从架构的消息无法享受dLedger集群的两阶段同步功能。
3、启动
nameserver之前启动过了,可参考上面的nameserver启动
三台机器worker-rocketmq1、worker-rocketmq2、worker-rocketmq3都切换到rocketmq的home目录下执行
bash
nohup bin/mqbroker -c conf/dledger/broker.conf &
4、检查集群服务状态
dashboard控制台可以查看到集群的运行状态

leader节点执行bin/mqshutdown broker后的结果

Dledger集群如何防止脑裂问题的
- 多数派选举:选举领导者时遵循多数派原则,确保同一时刻集群最多只有一个领导者。
- 任期机制:通过单调递增的任期号,让节点优先处理高任期号请求,避免旧领导者在新任期工作。
- 心跳机制:领导者定期发心跳,跟随者若未按时收到则发起选举,及时发现领导者故障。
- 日志复制与检查:领导者复制日志到跟随者,多数节点复制成功才标记提交,节点会检查并同步日志,保证集群状态一致。