前言
一直以来,我都觉得如果只是会用消息队列,还不足以真正理解它的价值。想要在架构层面做出更好的技术决策,就必须深入了解 MQ 的底层原理、消息存储机制以及高可用设计。所以我决定亲手搭建一套 RocketMQ 集群,从实践中去理解它的设计思想与实现细节。相比于单纯阅读文档或源码,实际动手部署、调试、观察日志,能更直观地体会到消息在系统中的流转过程 。
写这篇博客,一方面是为了提升自己对消息队列的理解深度 ,另一方面也是为了为后续的技术成长打下基础。毕竟,只有真正理解底层原理,才能在未来的架构设计和系统优化中,更自信地做出技术选择,并说服他人接受你的方案。
准备
Linux 服务器并且已安装 docker 环境、docker-compose 环境
实践
RocketMQ 镜像获取
1.直接在线拉取镜像
- 拉取 rocketmq 镜像
bash
docker pull apache/rocketmq:5.2.0
- 拉取rocketmq-dashboard 面板镜像
bash
docker pull apacherocketmq/rocketmq-dashboard:2.1.0
2.手动上传构建镜像
从 2024 年开始许多的国内商用服务器无法直接通过命令拉取 docker 镜像,所以只有下载镜像包后再上传到自己服务器构建
- 镜像包可参考开源项目自行构建下载:GitHub - wukongdaily/DockerTarBuilder: 它是一个工作流。可快速构建指定架构/平台的docker镜像
- 觉得麻烦的也可直接下载博主已经构建好的镜像包:
链接: pan.baidu.com/s/1pHqpOgZy... 提取码: mffw
3.上传镜像包到自己服务器的指定文件夹中
4.进入该文件夹执行构建镜像命令
bash
docker load -i apache_rocketmq_5.2.0-amd64.tar.gz
bash
docker load -i apacherocketmq_rocketmq-dashboard_2.1.0-amd64.tar.gz
5.等命令执行完成查看镜像已存在
RocketMQ 服务配置说明
在搭建 最小可运行的 RocketMQ 集群 时,通常需要启动以下四个核心组件
- NameServer:作为注册中心,负责维护 Broker 的路由信息,Producer 和 Consumer 都通过它来获取消息路由。
- Broker Master:主节点,负责消息的接收、存储和投递,是消息真正的存储载体。
- Broker Slave:从节点,用于实时同步 Master 的消息数据,起到备份和高可用的作用。
- RocketMQ Dashboard:可视化管理控制台,用于查看消息、监控集群运行状态及管理 Topic、消费组等。
在实际部署中,强烈建议同时部署 Master 和 Slave 。虽然单个 Master 就能完成基本功能,但引入 Slave 节点可以显著提升系统的 高可用性(HA) 。当 Master 节点发生异常时,Slave 可以保证已经发送的消息可以正常被消费者消费而不会丢失,从而保证消息数据的可靠性。这也是 RocketMQ 官方推荐的标准部署方案。
创建宿主机挂载文件夹/文件
在服务器自定义位置创建 rocketmq 文件夹,并创建以下文件夹和文件
arduino
mkdir 文件夹 -p
1. NameServer 创建挂载文件
1.在 namesrv 文件夹中创建 logs、bin 文件夹
2.设置 namesrv 文件夹读写权限
bash
chmod 777 -R /home/docker/rocketmq/namesrv/*
3.启动 nameserver 临时容器
bash
docker run -d \
--privileged=true \
--name rmqnamesrv \
apache/rocketmq:5.2.0 sh mqnamesrv
4.复制容器内启动脚本到挂载目录/home/docker/rocketmq/namesrv/bin
bash
docker cp rmqnamesrv:/home/rocketmq/rocketmq-5.2.0/bin/runserver.sh /home/docker/rocketmq/namesrv/bin/runserver.sh
5.修改runserver.sh 脚本文件:找到调用calculate_heap_sizes函数的位置注释掉保存即可
嫌麻烦的也可直接使用博主修改完成的内容
bash
#!/bin/bash
error_exit ()
{
echo "ERROR: $1 !!"
exit 1
}
find_java_home()
{
case "`uname`" in
Darwin)
JAVA_HOME=$(/usr/libexec/java_home)
;;
*)
JAVA_HOME=$(dirname $(dirname $(readlink -f $(which javac))))
;;
esac
}
find_java_home
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && error_exit "Please set the JAVA_HOME variable in your environment, We need java(x64)!"
export JAVA_HOME
export JAVA="$JAVA_HOME/bin/java"
export BASE_DIR=$(dirname $0)/..
export CLASSPATH=.:${BASE_DIR}/conf:${CLASSPATH}
#===========================================================================================
# JVM Configuration
#===========================================================================================
# Dynamically calculate parameters, for reference.
Xms=$MAX_HEAP_SIZE
Xmx=$MAX_HEAP_SIZE
Xmn=$HEAP_NEWSIZE
# Set for `JAVA_OPT`.
JAVA_OPT="${JAVA_OPT} -server -Xms${Xms} -Xmx${Xmx} -Xmn${Xmn}"
JAVA_OPT="${JAVA_OPT} -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC"
JAVA_OPT="${JAVA_OPT} -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
$JAVA ${JAVA_OPT} $@
6.停止并且删除 nameserver 临时容器
bash
docker stop rmqnamesrv
docker rm -f rmqnamesrv
2. Broker 创建挂载文件
1.在 broker 以及 broker-slave 文件夹中分别创建文件夹 conf、data、logs、store、bin
2.分别为 broker 以及 broker-slave 文件夹设置读写权限
bash
chmod 777 -R /home/docker/rocketmq/broker/*
chmod 777 -R /home/docker/rocketmq/broker-slave/*
如果未设置权限或者设置失败,那么容器会启动失败并且启动日志报找不到文件的相关异常
3.启动临时 broker 容器
bash
docker run -d --name rmqbroker --privileged=true apache/rocketmq:5.2.0 sh mqbroker
4.拷贝启动脚本runbroker.sh 到 broker 以及 broker-slave 的 bin 文件夹中
bash
docker cp rmqbroker:/home/rocketmq/rocketmq-5.2.0/bin/runbroker.sh /home/docker/rocketmq/broker/bin/runbroker.sh
docker cp rmqbroker:/home/rocketmq/rocketmq-5.2.0/bin/runbroker.sh /home/docker/rocketmq/broker-slave/bin/runbroker.sh
同理删除文件中calculate_heap_sizes函数,也可直接拷贝上面 namesrv 的文件配置
5.拷贝持久化核心目录配置文件 /store/config
bash
docker cp rmqbroker:/home/rocketmq/store/config /home/docker/rocketmq/broker/store/config
docker cp rmqbroker:/home/rocketmq/store/config /home/docker/rocketmq/broker-slave/store/config
注:这个文件夹内容很重要,如果没有启动也会报找不到文件异常错误
6.配置 broker master 服务配置文件broker.conf
在 /broker/conf 文件夹中配置 新建broker.conf 文件并配置
bash
# 集群名称
brokerClusterName = DefaultCluster
# 节点名称
brokerName = broker-a
# broker id节点ID, 0 表示 master, 其他的正整数表示 slave,不能小于0
brokerId = 0
# Broker服务地址 String 内部使用填内网ip,如果是需要给外部使用填公网ip,自行更改
brokerIP1 = 服务器对外可访问ip
# 配置HA端口 同步 slave broker
haListenPort= 10908
#对外开发端口
listenPort= 10911
# Broker角色
brokerRole = ASYNC_MASTER
# 刷盘方式
flushDiskType = ASYNC_FLUSH
# 在每天的什么时间删除已经超过文件保留时间的 commit log,默认值04
deleteWhen = 04
# 以小时计算的文件保留时间 默认值72小时
fileReservedTime = 72
# 是否允许Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
# 是否允许Broker自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
storePathRootDir=/home/rocketmq/store
storePathCommitLog=/home/rocketmq/store/commitlog
storePathConfig=/home/rocketmq/store/config
7.配置 broker slave 服务配置文件broker.conf
在 /broker-slave/conf 文件夹中配置 新建broker.conf 文件并配置
bash
# 集群名称
brokerClusterName = DefaultCluster
# 节点名称
brokerName = broker-a
# broker id节点ID, 0 表示 master, 其他的正整数表示 slave,不能小于0
brokerId = 1
masterAddr= rmqbroker:10911 # 指向 Master
brokerRole= SLAVE
flushDiskType= ASYNC_FLUSH
listenPort= 10912 # 不和 Master 冲突
haListenPort= 10913 # HA 端口可改
# 是否允许Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
# 是否允许Broker自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
storePathRootDir=/home/rocketmq/store
storePathCommitLog=/home/rocketmq/store/commitlog
storePathConfig=/home/rocketmq/store/config
属性特别说明:
- brokerClusterName、brokerName 属性值必须和 broker master 的配置相同
- masterAddr 属性中的 rmqbroker 为 broker master 容器启动后的名称(可现在定义,后续启动时保持一直就行)。也可替换为 master 容器的内部 ip(masterAddr= 172.21.0.4:10911), 在后续启动完 broker master 容器后执行下面命令获取
bash
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 容器名称
8.停止并删除 broker 临时容器
bash
docker stop rmqbroker
docker rm rmqbroker
3.编写docker-compose.yml文件
回到外层编辑 docker 容器编排文件
该文件将 nameserver、broker master、broker slave、rocketmq Dashboard 都进行了编排配置。
注意文件中的配置顺序也必须安装这个顺序设置
bash
version: '3.8'
services:
rmqnamesrv:
image: apache/rocketmq:5.2.0
container_name: rmqnamesrv
ports:
- 9876:9876
restart: always
privileged: true
volumes:
- /home/docker/rocketmq/namesrv/logs:/home/rocketmq/logs
- /home/docker/rocketmq/namesrv/bin/runserver.sh:/home/rocketmq/rocketmq-5.2.0/bin/runserver.sh
environment:
- MAX_HEAP_SIZE=256M
- HEAP_NEWSIZE=128M
command: ["sh","mqnamesrv"]
rmqbroker:
image: apache/rocketmq:5.2.0
container_name: rmqbroker
ports:
- 10911:10911
- 10908:10908
restart: always
privileged: true
volumes:
- /home/docker/rocketmq/broker/logs:/home/rocketmq/logs
- /home/docker/rocketmq/broker/store:/home/rocketmq/store
- /home/docker/rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.2.0/conf/broker.conf
- /home/docker/rocketmq/broker/bin/runbroker.sh:/home/rocketmq/rocketmq-5.2.0/bin/runbroker.sh
depends_on:
- 'rmqnamesrv'
environment:
- NAMESRV_ADDR=rmqnamesrv:9876
- MAX_HEAP_SIZE=256M
- HEAP_NEWSIZE=128M
command: ["sh","mqbroker","-c","/home/rocketmq/rocketmq-5.2.0/conf/broker.conf"]
rmqbroker-slave:
image: apache/rocketmq:5.2.0
container_name: rmqbroker-slave
ports:
- 10912:10912
restart: always
privileged: true
volumes:
- /home/docker/rocketmq/broker-slave/logs:/home/rocketmq/logs
- /home/docker/rocketmq/broker-slave/store:/home/rocketmq/store
- /home/docker/rocketmq/broker-slave/conf/broker.conf:/home/rocketmq/rocketmq-5.2.0/conf/broker.conf
- /home/docker/rocketmq/broker-slave/bin/runbroker.sh:/home/rocketmq/rocketmq-5.2.0/bin/runbroker.sh
depends_on:
- 'rmqnamesrv'
environment:
- NAMESRV_ADDR=rmqnamesrv:9876
- MAX_HEAP_SIZE=256M
- HEAP_NEWSIZE=128M
command: ["sh","mqbroker","-c","/home/rocketmq/rocketmq-5.2.0/conf/broker.conf"]
rmqdashboard:
image: apacherocketmq/rocketmq-dashboard:2.1.0
container_name: rocketmq-dashboard
ports:
- 8082:8082
restart: always
privileged: true
depends_on:
- 'rmqnamesrv'
environment:
- JAVA_OPTS= -Xmx256M -Xms256M -Xmn128M -Drocketmq.namesrv.addr=rmqnamesrv:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false
注:如果你的文件路径 以及端口都和本文不一致,那么需要在对应文章就行调整
注:配置中涉及到的端口 也需要在服务器的安全组中进行开放
注:由于博主的服务器运行内存比较低,所以在配置文件中对每个服务的堆栈大小进行了调整(可据自己服务情况进行调整)
MAX_HEAP_SIZE=256M
HEAP_NEWSIZE=128M
启动 rocketmq 容器相关服务
进入 docker-comsose.yml 同级目录,执行命令构建容器
docker compose up -d
执行完成查看容器
docker ps
结果与验证
1.访问 rocketmq 面板:外网ip:8082
可以看到 broker 的主从服务也都启动成功
2.验证 broker 主从服务是否正常同步消息
创建 topic 并且发送消息
进入服务器 broker master 的/home/docker/rocketmq/broker/store/consumequeue
进入服务器 broker slave 的/home/docker/rocketmq/broker-slave/store/consumequeue
发现他们的 topic 文件夹相同并且创建时间一样,则表示同步成功。
也可查看 commitlog 文件

文件大小、偏移量以及创建时间都一致。