RocketMQ 集群部署实战:为什么我选择自己搭建,而不是现成方案

前言

一直以来,我都觉得如果只是会用消息队列,还不足以真正理解它的价值。想要在架构层面做出更好的技术决策,就必须深入了解 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 镜像,所以只有下载镜像包后再上传到自己服务器构建

  1. 镜像包可参考开源项目自行构建下载:GitHub - wukongdaily/DockerTarBuilder: 它是一个工作流。可快速构建指定架构/平台的docker镜像
  2. 觉得麻烦的也可直接下载博主已经构建好的镜像包:

链接: 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 文件

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

相关推荐
报错小能手3 小时前
linux学习笔记(26)计算机网络基础
linux·笔记·学习
盛满暮色 风止何安4 小时前
防火墙的类别和登录Web的方法
linux·运维·服务器·网络·网络协议·tcp/ip·网络安全
铭哥的编程日记4 小时前
【Linux】库制作与原理
android·linux·运维
shan~~5 小时前
linux安装海量数据库和操作
linux·数据库·oracle
JAVA学习通5 小时前
Docker 安装 Harbor 教程
运维·docker·容器
qq_203183575 小时前
flink的Standalone-HA模式安装
linux
乌萨奇也要立志学C++5 小时前
【Linux】进程控制(二) 深入理解进程程序替换与 exec 系列函数
linux·运维·服务器
ShareBeHappy_Qin5 小时前
Linux 命令 —— 常用命令总结
linux·运维·服务器
Ronin3055 小时前
【Linux网络】Socket编程:TCP网络编程
linux·网络·网络编程·tcp