☰
RocketMQ 5.x Docker部署避坑指南:从Proxy架构到容器编排
2026/10/23 3:48:52 网站建设 项目流程

如果现在还按着 RocketMQ 4.x 那套 docker run 习惯去部署 5.x,大概率会踩到同一个坑:broker 起来了,日志也没报错,但客户端就是发不出去消息,或者消息发出去了控制台却显示 broker 下线。原因很简单,5.x 在架构里塞了一个叫 Proxy 的组件,容器端口、注册发现、客户端协议全变了。这篇文章就顺着我实际操作跑通的 5.3.x 单机部署过程,把镜像选择、网络规划、compose 编排、broker 参数、客户端接入和问题排查一次讲清楚,适合刚接触 RocketMQ 5.x、或者从 4.x 升上来的团队参考。

1. 部署前先把 RocketMQ 5.x 的架构变化理清楚

1.1 为什么 5.x 部署和 4.x 完全不是一回事

RocketMQ 4.x 时代,一个集群最核心的就两个角色:NameServer 负责注册发现,Broker 负责消息存储和收发,客户端走 Remoting 协议直接连 Broker 的 10911 端口。这个模型很直观,部署也简单,两条 docker run 就能拉到一套可用的环境。

5.x 最大的变化是引入了 Proxy 这个无状态接入层。Proxy 对外提供 gRPC 和 HTTP 协议,对内再通过 Remoting 协议和 Broker 通信。客户端不再需要直接面对 Broker,而是先找 NameServer,再连 Proxy。这个设计的好处很明显:协议适配、权限校验、流控这些事都沉淀在 Proxy 层,Broker 可以更专注于存储和复制。但落到 Docker 部署上,就意味着端口变多了,容器角色变多了,broker.conf 里的关键参数也变了。

我见过不少从 4.x 切过来的朋友,直接复制旧命令,把 broker 的 10911 端口映射出来,然后客户端也打通了,结果发现新版客户端默认走 8081 的 gRPC 端口,根本没有映射出去。这不是配置错了,是架构变了之后,部署方案还停留在旧版本。

1.2 Docker 部署的五项前置准备

如果你打算照着这篇文章走一遍,先确认下面五件事。

第一,服务器配置。单机测试环境建议至少 2 核 4G,Docker 桌面版的话要给虚拟机分配到 4G 以上内存,否则 Broker 进程很容易因为内存不足被系统杀掉。第二,Docker 版本。尽量用 Docker 20.10 以上,docker compose 命令是独立插件也没关系,语法兼容即可。第三,磁盘空间。RocketMQ 的 store 目录会持续增长,测试环境也建议留 20G 以上,别把 store 挂到系统根目录分区,后面我会解释为什么。第四,出网环境。需要能正常拉取 Docker Hub 上的官方镜像,如果拉取慢,提前配置好镜像加速器。第五,本项目所有操作都在一台 Linux 主机上完成,Windows 用户建议先用 WSL2,纯 Windows 容器模式跑 RocketMQ 会遇到文件权限和网络模式的各种怪问题。

2. 镜像、网络、存储和端口,四件套怎么选

2.1 镜像选择:官方镜像与版本 tag 怎么挑

RocketMQ 5.x 的官方镜像仓库名是 apache/rocketmq,版本 tag 从 5.3.0 开始就是标准的语义化版本了。我这边用 5.3.1 做过完整验证,5.3.x 系列的部署方式基本一致。

我强烈建议直接用官方镜像,别用网上那些“全家桶”镜像。我理解大家想省事,但第三方镜像经常把版本号隐藏掉,你很难知道里面到底装的是 5.3.0 还是 5.2.0,更麻烦的是,别人改过启动脚本之后,你排查问题时看到的日志路径和命令行为都不一样,社区方案完全没法对齐。安全角度也是一个问题,镜像层的来源不透明,等于把一个未知身份的进程放进了生产环境里。

控制台镜像推荐用 apacherocketmq/rocketmq-dashboard。注意别再用以前那个 rocketmq-console-ng 的名字了,那个镜像已经停止维护,功能也老旧。

镜像 tag 的选择上,测试环境可以用 latest,但生产环境一定要锁定具体版本号,比如 apache/rocketmq:5.3.1。这样后面随便哪一天重新拉镜像,都不会因为 latest 漂移导致集群混版。

2.2 网络模式:桥接网络是默认解,但不是唯一解

Docker 部署中间件,网络模式主要就是 bridge、host 和自定义 bridge 三种。RocketMQ 5.x 我建议用自定义 bridge 网络。

原因很简单,NameServer、Broker、Proxy、Dashboard 几个容器之间需要互相访问,自定义 bridge 网络里可以直接用服务名当 hostname,配置里写 namesrv:9876 就完事,不用去查容器 IP。而默认的 bridge 网络在 docker compose 里虽然也能用服务名,但有些环境下 DNS 解析不够稳定,自定义网络更可控。

host 网络模式我也试过,性能确实好一点,省了一层 NAT,但代价是端口全部暴露在宿主机上,而且容器内拿到的 IP 就是宿主 IP,brokerIP1 这个参数会变得很别扭。还有一点很关键,在 mac 的 Docker Desktop 上,host 网络模式根本不支持,跨容器互通也有问题,折腾半天不如直接桥接。

部署脚本里我会创建一个独立的网络,名字随意,关键是让 compose 项目内的服务自动加入这个网络,服务名就是容器间的通信地址。

2.3 存储卷、目录权限与容器内 store 结构

RocketMQ 容器最怕的就是“起来就挂”。很多次部署失败,最后定位到的原因不是配置写错,而是宿主机的挂载目录没有给容器内的用户写权限。

官方镜像默认以名为 rocketmq 的用户运行,这个用户的 UID 通常是 3000,但不同版本可能不一样。你把宿主目录挂进容器之后,如果这个目录属于 root,容器内进程根本写不进去,Broker 启动时会尝试创建 commitlog 目录,直接报 Permission denied。

我习惯的做法是先在宿主机建好目录结构,然后统一 chown。

mkdir -p /data/rocketmq/{store,logs,conf} chown -R 3000:3000 /data/rocketmq

store 目录下会分成 commitlog、consumequeue、index 三个核心子目录。commitlog 存消息主体,consumequeue 存消费逻辑队列,index 用于按 key 查消息。这三块数据最好都落在同一个数据盘,避免和系统日志抢 IO。

2.4 端口全景:一张表记住所有常驻端口

RocketMQ 5.x 的端口比 4.x 多,而且存在同名端口冲突,需要整体规划。我整理了一张表,部署前先扫一眼。

端口归属组件作用
9876NameServer注册发现端口,客户端和 Broker 都要连
10911Broker主监听端口,4.x 客户端走 Remoting 协议连这个
10909Broker VIP 端口高可用内部通信使用,建议一并映射
8081ProxygRPC 接入端口,5.x 新客户端默认走这里
8080ProxyHTTP 接入端口,也可以给 Dashboard 用,两个容易撞
8080DashboardWeb 控制台,容器内默认端口也是 8080

我强烈建议把 Dashboard 映射到宿主机的 18080,把 8080 让给 Proxy 用。这样客户端走 gRPC 的 8081 不会乱,HTTP 调试走 8080 也不会跟控制台打架。

3. 实操部署:从模板文件到一条 compose 拉起来

3.1 目录初始化与 broker.conf 逐行解析

先准备 broker 的配置文件,我放在 /data/rocketmq/conf/broker.conf。下面的示例是单机部署最简可用版,每一行都有它的用途。

brokerClusterName=DefaultCluster brokerName=broker-a brokerId=0 namesrvAddr=namesrv:9876 brokerIP1=192.168.1.100 listenPort=10911 storePathRootDir=/home/rocketmq/store storePathCommitLog=/home/rocketmq/store/commitlog autoCreateTopicEnable=true autoCreateSubscriptionGroup=true brokerMode=Local

brokerClusterName 和 brokerName 只是逻辑命名,单机环境可以随便起,但集群环境下 brokerName 要保证同一组主从节点一致。namesrvAddr 这里写的是 namesrv,这是 docker compose 里的服务名,容器间通信靠这个,别写成 127.0.0.1。

brokerIP1 这个参数是很多人栽跟头的地方。它决定了 Broker 向 NameServer 注册时上报的对外地址。如果不配置,容器里的 Broker 会默认把容器 IP 报上去,客户端在宿主机外拿到这个 IP 根本连不上。所以单机部署要给 brokerIP1 配成宿主机 IP。后面验证集群状态时,如果你的 brokerAddr 显示成了 192.168.x.x 而不是 172.17.0.x,说明这一步没白做。

listenPort 保持默认 10911 就行,没有特殊需求不要乱改,改了之后客户端配置也要联动更新。

storePathRootDir 和 storePathCommitLog 要指向容器内的路径。虽然宿主机挂载了 /data/rocketmq/store,但容器里看到的路径是 /home/rocketmq/store,配置一定按容器视角写。

autoCreateTopicEnable 和 autoCreateSubscriptionGroup 测试阶段建议 true,省得到处手工建 topic。生产环境如果你们有 topic 审批流程,记得取消自动创建,改成由运维统一创建。

brokerMode=Local 是这个配置文件里最关键的一行。它表示 Proxy 直接嵌入在 Broker 进程内,一个容器同时承担 Broker 和 Proxy 两个角色。如果是 Cluster 模式,Proxy 要单独部署一个容器,复杂度更高,单机测试完全没必要。

3.2 docker-compose.yml 完整模板

我这边直接用 docker compose 管理,相比裸 docker run,好处是网络自动创建、服务依赖关系清楚、重启一键完成。下面是完整的编排文件。

version: '3.8' services: namesrv: image: apache/rocketmq:5.3.1 container_name: rmqnamesrv ports: - "9876:9876" environment: - MAX_POSSIBLE_HEAP=256m command: sh mqnamesrv restart: unless-stopped broker: image: apache/rocketmq:5.3.1 container_name: rmqbroker ports: - "10911:10911" - "10909:10909" - "8080:8080" - "8081:8081" environment: - MAX_POSSIBLE_HEAP=512m - NAMESRV_ADDR=namesrv:9876 volumes: - /data/rocketmq/conf/broker.conf:/etc/rocketmq/broker.conf - /data/rocketmq/logs:/home/rocketmq/logs - /data/rocketmq/store:/home/rocketmq/store command: sh mqbroker -n namesrv:9876 -c /etc/rocketmq/broker.conf depends_on: - namesrv restart: unless-stopped dashboard: image: apacherocketmq/rocketmq-dashboard:latest container_name: rmqdashboard ports: - "18080:8080" environment: - JAVA_OPTS=-Drocketmq.namesrv.addr=namesrv:9876 depends_on: - namesrv restart: unless-stopped

namesrv 服务很简单,指定 heap 上限,启动命令就是 sh mqnamesrv。MAX_POSSIBLE_HEAP 这个环境变量是官方镜像脚本识别的,用来限制 JVM 堆大小。单机环境 Nameserver 只需要注册发现,256m 足够。

broker 服务是重点。镜像还是同一个 apache/rocketmq:5.3.1,因为 Proxy 内嵌在 Broker 里,所以要把 8080 和 8081 一起映射出来。命令里我同时加了 -n namesrv:9876 和 -c 指定配置文件,双保险。depends_on 只保证启动顺序,不代表 namesrv 已经就绪,所以后面启动后要看日志确认。

dashboard 镜像的 JAVA_OPTS 环境变量里写 namesrv 地址,启动后就不用再手填了。latest tag 在测试环境没太大问题,生产建议换个固定版本。

配置文件的路径我挂载到 /etc/rocketmq/broker.conf,这个路径在镜像里不存在也没关系,挂载会自动创建容器内父目录,关键是 -c 参数要和它一致。

3.3 启动验证:日志怎么读、集群状态怎么看

执行下面命令前,确保目录和配置文件都放好了。

cd /data/rocketmq docker compose up -d

第一次启动会拉镜像,耐心等一会。起来之后别急着下结论,先看进程状态。

docker ps

正常情况应该有三个容器,状态都是 Up。如果某个容器一直 Restarting,多半是配置有问题,优先看日志。

docker logs rmqnamesrv docker logs rmqbroker

Nameserver 的日志出现“boot success”字样就是启动成功。Broker 日志里同样找“boot success”,如果看到异常堆栈,重点看有没有 Permission denied、Address already in use、No space left on device这几类关键词。

进程起来不代表集群注册成功,一定要用 mqadmin 命令确认。

docker exec -it rmqbroker bash export PATH=$PATH:/home/rocketmq/rocketmq-5.3.1/bin mqadmin clusterList -n namesrv:9876

如果提示 mqadmin 找不到,说明镜像里脚本目录不在 PATH 里,用 find /home/rocketmq -name mqadmin 找到路径再补上去。clusterList 能看到 brokerName、brokerAddr、版本信息,其中 brokerAddr 显示的应该是你配的 brokerIP1 加上 10911,比如 192.168.1.100:10911,而不是容器 ID 或者 172.17 网段地址。看到这个结果,这一套部署才算真正通了。

4. 部署完成后必须处理的三个生产细节

4.1 客户端接入方式差异与 brokerIP1 的坑

RocketMQ 5.x 的客户端分成两类,接入路径完全不同,很值得展开说一下。

第一类是 4.x 风格客户端,比如 com.alibaba.rocketmq 的旧依赖。它走 Remoting 协议,直连 Broker 的 10911 端口。这类客户端通过 namesrvAddr 配置 nameserver 地址,然后从 nameserver 拿 broker 地址列表,再直连 broker。这时候 brokerIP1 配置错了,客户端拿到的 broker 地址就是容器内网 IP,连接会超时。

第二类是 5.x 新客户端,依赖是 org.apache.rocketmq:rocketmq-client-java。它默认走 gRPC 协议,连接的是 Proxy 的 8081 端口,不直接碰 broker。新客户端的接入配置更简单,只需要提供 nameserver 地址,它自己会从 nameserver 获取 proxy 地址列表。但同样要注意,Proxy 向 nameserver 注册的地址必须是客户端能访问到的地址,如果 proxy 上报的是容器 IP,还是会连不上。

实际操作中我建议测试阶段先用 4.x 风格客户端或者工具验证 broker 本身没问题,再切新客户端验证 proxy 链路。出了问题也能快速区分是 broker 的问题还是 proxy 的问题。

另外提醒一句,如果你们的客户端版本很低,比如 3.x 时代的老古董,跟 5.x server 的兼容性需要单独验证,别指望直接升级 server 就能通。

4.2 容器资源与 JVM 调优

RocketMQ 默认的 JVM 参数是按物理机部署设计的,堆内存动不动给到 4G、8G。放进容器里不调整,小内存服务器直接 OOM。

官方镜像预留了 MAX_POSSIBLE_HEAP 这个环境变量,我前文的 compose 文件已经给 namesrv 和 broker 分别设了 256m 和 512m,这是测试环境的合理值。生产环境建议按照业务量来,broker 的堆内存一般给到系统物理内存的 1/4 到 1/2,同时要留出页缓存给操作系统。

如果还想进一步控制,可以用 JAVA_OPT_EXT 环境变量传额外的 JVM 参数,比如:

JAVA_OPT_EXT=-Xms512m -Xmx512m -Xmn256m

这里 -Xms 和 -Xmx 最好设置成相同值,避免 JVM 运行时动态扩容触发性能抖动。-Xmn 是年轻代大小,消息写入主要在年轻代完成,分配不合理会导致频繁 Minor GC。

还有一层防护是 Docker 容器层面的资源限制。compose 文件里可以加 mem_limit,比如:

broker: mem_limit: 2g cpus: 2

万一 JVM 参数写错或者内存泄漏,容器最多吃 2G,不至于把整个宿主拖垮。OOM 之后容器可能直接退出,这时候 docker inspect 看 OOMKilled 字段是最快的定位手段。

4.3 Dashboard 监控和日志处理

Dashboard 启动后,浏览器访问 http://宿主IP:18080,如果 JAVA_OPTS 里配了 namesrv 地址,首页就能看到集群信息。如果看不到,先在右上角手动填入 namesrv:9876,再点切换。

Dashboard 上主要看三块:broker 存活状态、topic 的生产消费速率、积压消息数量。积压数量是消费端最容易出问题的指标,某个 consumer group 的积压持续上涨,基本就是消费逻辑出 bug 了。

日志方面,RocketMQ 容器里有两类日志。一类是 stdout,docker logs 能直接看到,主要打印启动流程和异常堆栈。另一类是文件日志,在挂载出来的 /data/rocketmq/logs 目录里,包含 broker 的运行日志、存储相关日志、GC 日志等。我建议把日志目录接到公司现有的采集链路里,不然排查问题的时候翻容器内部的日志文件,路径又长又不方便。

还有一点,GC 日志默认也是写到日志目录的,如果你们的日志采集会扫描全部文件,别把 GC 日志误当成业务日志告警,规则上提前排除掉。

5. 高频故障排查与避坑记录

5.1 故障速查表:现象、原因、对策一次对齐

下面的表格是从实际操作中整理出来的高频故障,每一类都真实遇到过。

故障现象常见原因处理方式
broker 容器一直 Restartingbroker.conf 路径不对或目录无权限docker logs 看具体报错,检查挂载目录权限
日志显示 Permission deniedstore 目录属主不对chown -R 3000:3000 宿主机挂载目录
客户端连接 9876 超时nameserver 没启动或防火墙拦截docker ps 确认容器状态,检查宿主防火墙规则
客户端拿到 broker 地址无法连接brokerIP1 未配置或配置成内网容器 IP改成宿主机外网可访问 IP,重启 broker
新客户端连接 proxy 失败8081 端口没映射到宿主机compose 里补上 8080/8081 端口映射
dashboard 页面无法访问8080 端口被 proxy 占用冲突dashboard 映射改到 18080
broker 进程被 OOM 杀掉MAX_POSSIBLE_HEAP 设置过大调小堆内存,容器加 mem_limit
磁盘报警,store 目录持续增长消息保留时间配置过长调 deleteWhen 和 fileReservedTime,定期清理

很多问题表象一样,根因完全不同。比如客户端 9876 超时,既可能是 nameserver 容器挂了,也可能是防火墙拦截,还可能是在 compose 网络里客户端容器和服务端容器不在同一个网络。排查顺序我建议是:容器状态 -> 端口监听 -> 防火墙 -> 配置内容。

5.2 两个典型排查过程实录

第一个典型场景:客户端连上了 nameserver,但发消息一直超时。

我当时第一反应是网络问题,在宿主上用 telnet 测了 10911,端口是通的。再看客户端日志,发现它拿到的 brokerAddr 是 172.17.0.3:10911 这种容器内网地址,这下真相清楚了。容器网络里 broker 上报的是它自己的容器 IP,而客户端在宿主机上,根本路由不到 172.17 网段。解决方式就是前面讲的,brokerIP1 配置成宿主机可路由的 IP,然后重启 broker。重启完再用 mqadmin clusterList 确认 brokerAddr 变成了预期地址。

第二个典型场景:broker 启动后没过几分钟就退出,docker ps 看状态一直 Restarting。

先 docker logs 看日志,发现存储模块报错 No space left on device。当时的 store 挂载目录在系统根分区上,根分区只有 20G,跑了一晚上就把磁盘填满了。这个问题的深层原因是 commitlog 文件默认单个 1G,消息量大之后文件增长很快,旧文件的保留策略又没调,磁盘瞬间打满。处理方法是把 store 迁移到独立数据盘,然后调低 fileReservedTime,比如改成 72,只保留 72 小时内的消息文件。

5.3 最后再分享一个部署习惯

走完上面这些步骤,一套单机 RocketMQ 5.x 已经能稳定跑业务了。最后分享一个我自己坚持了很久的习惯:任何中间件的 Docker 部署,都不要裸用 docker run,统一用 docker compose 管理,并且把配置文件纳入版本库。

裸 docker run 的问题在于,你很难追溯上一次是怎么启动的。今天加个参数,明天改个端口,时间一长,部署记录和实际环境就对不上了。compose 文件本身就是部署清单,团队成员 review、环境迁移、故障重建,都靠这一份文件。

RocketMQ 5.x 的容器化部署其实不难,真正容易踩坑的是架构变化带来的连锁反应:新端口、新组件、新协议。一次部署把 4.x 到 5.x 的差异逐项确认一遍,之后再从单机扩到主从集群、双副本集群,配置上的思路就是顺理成章的事了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询