
博主简介CSDN博客专家「历代文学网」PC端可以访问https://lidaiwenxue.com/#/?__c1000移动端可关注公众号 “心海云图” 微信小程序搜索“历代文学”总架构师首席架构师也是联合创始人16年工作经验精通Java编程高并发设计分布式系统架构设计Springboot和微服务熟悉LinuxESXI虚拟化以及云原生Docker和K8s热衷于探索科技的边界并将理论知识转化为实际应用。保持对新技术的好奇心乐于分享所学希望通过我的实践经历和见解启发他人的创新思维。在这里我希望能与志同道合的朋友交流探讨共同进步一起在技术的世界里不断学习成长。商务合作请搜索或扫码关注微信公众号 “心海云图”RocketMQ 5.5.0 Docker 部署踩坑实录前言最近在将 RocketMQ 从 5.3.3 迁移到 5.5.0 的过程中选择了官方apache/rocketmq:5.5.0镜像并搭建了一套两主两从的 Docker 集群。本以为会是一个简单的版本升级没想到一路踩坑无数。本文将这些坑点逐一记录下来希望能帮助到正在或即将部署RocketMQ 5.5.0的你。环境说明操作系统CentOS 7 / Rocky Linux 8容器运行时Docker 20.10镜像版本apache/rocketmq:5.5.0实际使用registry.cn-hangzhou.aliyuncs.com/sinhy/rocketmq:5.5.0基于官方镜像重命名集群架构两主两从2m-2s-sync共 4 个 Broker 节点 2 个 NameServer 节点目录镜像内 UID 是 3000 而非 1000JVM 环境变量名称错了直接内存为何要设大JDK 8 不支持 --add-exportsSELinux 阻止容器写入挂载目录logs/rocketmqlogs 子目录需提前创建brokerName 和 brokerId 配置要唯一–network host 模式下 -p 端口映射失效store 目录为空正常现象总结一键部署脚本一、镜像内 UID 是 3000 而非 1000现象容器启动后日志无法写入挂载的宿主机目录。检查目录权限后发现已经执行了chown -R 1000:1000但依然报错Permission denied。原因官方apache/rocketmq:5.5.0镜像内部rocketmq用户的 UID 是3000而非常见的 1000。# 进入容器验证dockerexec-itbroker-a-10911id# 输出: uid3000(rocketmq) gid3000(rocketmq)很多周边项目如rocketmq-operator使用的是 UID 1000但官方核心镜像的标准是3000。解决方案挂载目录的所有者必须设置为 3000sudochown-R3000:3000 /data/docker-containers/rocketmq/brokersudochmod-R755/data/docker-containers/rocketmq/broker教训永远不要假设容器内用户的 UID直接用docker exec进去确认。二、JVM 环境变量名称错了现象明明在docker run中通过-e JAVA_OPTS...设置了 JVM 参数但ps aux | grep java看到的值仍是脚本默认值导致OutOfMemoryError: Direct buffer memory不断出现。原因RocketMQ 5.5.0 的启动脚本runbroker.sh/runserver.sh中读取的是JAVA_OPT_EXT环境变量而不是JAVA_OPTS或ROCKETMQ_OPTS。脚本中关键行JAVA_OPT${JAVA_OPT}${JAVA_OPT_EXT}解决方案使用正确的环境变量名-eJAVA_OPT_EXT-Xss512k -Xms512m -Xmx2048m -XX:MaxDirectMemorySize6g -XX:MetaspaceSize64m -XX:MaxMetaspaceSize256m教训不同版本的 RocketMQ 镜像可能使用不同的环境变量名务必查看runbroker.sh源码确认。三、直接内存为何要设大现象即使设置了JAVA_OPT_EXTBroker 仍报错java.lang.OutOfMemoryError: Direct buffer memory at org.apache.rocketmq.store.TransientStorePool.init(TransientStorePool.java:50)原因RocketMQ Broker 默认开启了TransientStorePool堆外内存池。该组件会初始化一组 DirectByteBuffer 作为循环复用的缓冲区其数量由transientStorePoolSize参数控制默认值为 5每个缓冲区的大小默认为 1GB。注意这 5 个缓冲区是池化复用的并非启动时一次性全部占用。实际占用取决于transientStorePoolSize和mappedFileSizeCommitLog的配置值。如果-XX:MaxDirectMemorySize设置的值过小无法满足TransientStorePool初始化时的内存申请JVM 就会抛出Direct buffer memory错误。解决方案方案一推荐将直接内存设为 6GB 或更高-eJAVA_OPT_EXT-XX:MaxDirectMemorySize6g ...方案二在broker-a.properties中调整TransientStorePool的缓冲区数量transientStorePoolSize4或者直接禁用transientStorePoolEnablefalse注意方案二会降低写入性能非必要不推荐。教训堆外内存池是 RocketMQ 高性能的关键但它需要足够的直接内存支撑。生产环境下建议MaxDirectMemorySize至少为-Xmx的 2-3 倍同时根据实际负载调整transientStorePoolSize。四、JDK 8 不支持--add-exports现象NameServer 启动报错Unrecognized option: --add-exports Error: Could not create the Java Virtual Machine.原因--add-exports是JDK 9引入的模块化系统参数用于跨模块导出包。如果底层的 JDK 是 8JVM 不认识这个参数直接拒绝启动。解决方案直接移除JAVA_OPT_EXT中的--add-exports参数或者添加-XX:IgnoreUnrecognizedVMOptions让 JVM 忽略它-eJAVA_OPT_EXT-XX:IgnoreUnrecognizedVMOptions ...教训如果你的镜像基于 JDK 8官方apache/rocketmq:5.5.0默认使用eclipse-temurin:8请避免使用 JDK 9 特有的 JVM 参数。五、SELinux 阻止容器写入挂载目录现象目录权限chownchmod全部正确甚至设置了777但容器内仍无法写入文件touch: cannot touch /home/rocketmq/logs/test.txt: Permission denied原因CentOS / RHEL 系列操作系统默认启用SELinux。即使宿主机目录权限放开了SELinux 策略也会阻止容器进程写入挂载的目录。解决方案方案一临时测试sudosetenforce0方案二永久关闭生产环境慎用sudosed-is/SELINUXenforcing/SELINUXdisabled/g/etc/selinux/configsudoreboot方案三给目录打标签推荐sudochcon-Rtsvirt_sandbox_file_t /data/docker-containers/rocketmq/broker教训权限问题不只有chown和chmodSELinux 是隐藏的大坑。遇到诡异权限问题时先setenforce 0测试一下。六、logs/rocketmqlogs子目录需提前创建现象宿主机挂载目录logs/为空即使 Broker 启动成功也没有日志文件。原因RocketMQ 的日志配置rmq.broker.logback.xml中日志输出路径为${user.home}/logs/rocketmqlogs/。容器在启动时如果/home/rocketmq/logs/rocketmqlogs/目录不存在可能因权限或挂载机制导致无法自动创建。解决方案在宿主机上提前创建好rocketmqlogs子目录sudomkdir-p/data/docker-containers/rocketmq/broker/a/logs/rocketmqlogssudochown-R3000:3000 /data/docker-containers/rocketmq/broker/a/logssudochmod-R755/data/docker-containers/rocketmq/broker/a/logs教训不要依赖容器内的程序自动创建多层目录尤其是涉及 Docker 挂载时提前创建是更保险的做法。七、brokerName和brokerId配置要唯一现象集群中某个从节点无法启动日志卡在 logback 配置加载后无任何错误信息。原因主从配置中从节点的brokerName与主节点重复或brokerId未设置为唯一值导致 Broker 注册到 NameServer 时发生冲突。解决方案确保每个 Broker 节点的配置文件中的关键字段正确# 主节点 brokerNamebroker-a brokerId0 # 从节点 brokerNamebroker-a-s brokerId1 # 从节点 0教训两主两从集群中4 个 Broker 的brokerName必须两两成对主从相同但主从之间用brokerId区分主0从0。八、--network host模式下-p端口映射失效现象启动容器时明明指定了-p 10911:10911但ss -tlnp看不到端口监听。原因当使用--network host时容器直接使用宿主机网络栈所有端口映射-p参数会被忽略且 Docker 会输出警告WARNING: Published ports are discarded when using host network mode解决方案如果需要端口映射不要使用--network host。在分布式部署中每个 Broker 部署在不同宿主机上使用--network host可简化网络配置此时-p可以移除。教训--network host是一把双刃剑简化网络配置的同时也会让端口管理更加透明也可能更混乱。九、store目录为空正常现象现象启动 Broker 后挂载的store目录为空没有任何子目录。结论这是正常的。store目录下的commitlog、consumequeue等子目录只有在 Broker收到并存储消息后才会自动创建。刚启动且未收发消息时store目录为空是预期行为。发送一条测试消息后目录结构会自动生成。教训不要因为空目录就以为 Broker 没启动好docker logs看到boot success才是关键证据。十、总结一键部署脚本以下是集成了所有踩坑修复的最终部署脚本单节点模板#!/bin/bash# # RocketMQ 5.5.0 Broker 部署脚本含所有坑修复# 用法在每台机器上执行修改 BROKER_ROLE 和 LISTEN_PORT# BROKER_ROLEa# 根据节点修改a, a-s, b, b-sLISTEN_PORT10911# 根据节点修改NAMESRV_ADDR172.16.10.90:9876;172.16.10.91:9876# 1. 创建目录包含 rocketmqlogs 子目录mkdir-p/data/docker-containers/rocketmq/broker/${BROKER_ROLE}/logs/rocketmqlogsmkdir-p/data/docker-containers/rocketmq/broker/${BROKER_ROLE}/storemkdir-p/data/docker-containers/rocketmq/broker/conf# 2. 修复权限注意UID 是 3000sudochown-R3000:3000 /data/docker-containers/rocketmq/broker/${BROKER_ROLE}sudochmod-R755/data/docker-containers/rocketmq/broker/${BROKER_ROLE}# 3. 关闭 SELinux或使用 chcon 打标签sudosetenforce0# 4. 启动容器dockerrun-d\--restartalways\--privilegedtrue\-p${LISTEN_PORT}:${LISTEN_PORT}\--volume/data/docker-containers/rocketmq/broker/${BROKER_ROLE}/logs:/home/rocketmq/logs\--volume/data/docker-containers/rocketmq/broker/${BROKER_ROLE}/store:/home/rocketmq/store\--volume/data/docker-containers/rocketmq/broker/conf/2m-2s-sync:/home/rocketmq/rocketmq/conf/2m-2s-sync\--namebroker-${BROKER_ROLE}-${LISTEN_PORT}\--networkhost\-eTZAsia/Shanghai\-eNAMESRV_ADDR${NAMESRV_ADDR}\-eJAVA_OPT_EXT-Xss512k -Xms512m -Xmx2048m -XX:MaxDirectMemorySize6g -XX:MetaspaceSize64m -XX:MaxMetaspaceSize256m\registry.cn-hangzhou.aliyuncs.com/sinhy/rocketmq:5.5.0\shmqbroker-c/home/rocketmq/rocketmq/conf/2m-2s-sync/broker-${BROKER_ROLE}.properties一句话锦囊RocketMQ 5.5.0 官方镜像部署四件套UID 用 3000JVM 用 JAVA_OPT_EXT直接内存给 6GSELinux 关掉。