末世的烘焙官
44.40M · 2026-03-22
最近在项目中引入 RocketMQ 作为消息中间件,选择使用 Docker 容器化部署以简化环境搭建。本以为按照官方文档几条命令就能搞定,结果连续踩了两个大坑:先是生产者发送消息超时,修复后 Console 管理界面又连不上 Broker。
如果你也在用 Docker 部署 RocketMQ,或者正准备搭建,希望这篇实录能帮你避开我踩过的坑。
读完本文,你将掌握:
RocketMQ 的 NameServer、Broker、Console 三个组件需要网络互通,创建一个独立的 Docker 网络是最佳实践:
# 创建 rocketmq 网络
docker network create rocketmq
# 验证网络创建成功
docker inspect rocketmq
为什么需要独立网络?
mqnamesrv:9876)docker pull apache/rocketmq:5.1.0
本文使用 RocketMQ 5.1.0 版本,这是目前较新的稳定版本。5.x 引入了 Proxy 代理层,架构与 4.x 有较大变化,后续会详细说明。
# NameServer 日志目录
mkdir -p /usr/local/rocketmq/nameserver/logs
chmod 777 -R /usr/local/rocketmq/nameserver/*
# Broker 日志和配置目录
mkdir -p /usr/local/rocketmq/broker/logs
mkdir -p /usr/local/rocketmq/broker/conf
chmod 777 -R /usr/local/rocketmq/broker/*
NameServer 是什么?
NameServer 是 RocketMQ 的轻量级路由注册中心,类似于 Dubbo 的 Zookeeper,但更简单:
docker run -d --name mqnamesrv -p 9876:9876 --network rocketmq
-v /usr/local/rocketmq/nameserver/logs:/home/rocketmq/logs
-e "MAX_HEAP_SIZE=256M"
-e "HEAP_NEWSIZE=128M"
apache/rocketmq:5.1.0 sh mqnamesrv
验证启动:
docker logs mqnamesrv
看到 The Name Server boot success 字样即表示启动成功。
Broker 与 Proxy 的关系
RocketMQ 5.x 引入了 Proxy 层,位于客户端和 Broker 之间:
Proxy 对外屏蔽了 NameServer、Broker 的概念,统一提供消息服务接口,同时支持多种协议(gRPC、HTTP 等)。
官方推荐使用 Local 模式部署,即 Broker 和 Proxy 同进程运行,减少网络开销。
docker run -d --name mqbroker -p 10911:10911 -p 10909:10909 --network rocketmq
-v /usr/local/rocketmq/broker/logs:/root/logs
-e "MAX_HEAP_SIZE=512M"
-e "HEAP_NEWSIZE=256M"
apache/rocketmq:5.1.0 sh mqbroker -n mqnamesrv:9876 --enable-proxy
autoCreateTopicEnable=true
-c /home/rocketmq/rocketmq-5.1.0/conf/broker.conf
端口说明:
10911:Broker 对外服务端口10909:Broker HA(高可用)端口验证启动:
docker exec -it mqbroker bash -c "tail -n 10 /home/rocketmq/logs/rocketmqlogs/proxy.log"
RocketMQ Console 是官方推荐的第三方管理工具,提供图形化界面用于监控消息堆积、消费者状态等。
docker run -d --name mqconsole -p 8098:8080 --network rocketmq
-e "JAVA_OPTS=-Xmx256M -Xms256M -Xmn128M
-Drocketmq.namesrv.addr=mqnamesrv:9876
-Dcom.rocketmq.sendMessageWithVIPChannel=false"
styletang/rocketmq-console-ng
访问 ;宿主机IP>:8098 即可看到控制台。
按照上述步骤部署后,Console 能正常连接,一切看起来很美好。但在 Spring Boot 应用中发送消息时:
rocketMQTemplate.syncSend("hotel-booking-test-topic:TEST_TAG", "Hello RocketMQ");
报错信息:
org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout
at org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl
通过排查日志和网络,发现问题出在 Broker IP 注册上:
问题链路:
172.18.0.3)注册172.18.0.3:10911,但这个 IP 在宿主机网络中不可达网络拓扑示意:
┌─────────────────┐
│ 生产者(宿主机) │
└────────┬────────┘
│ 查询路由
↓
┌─────────────────┐
│ NameServer │ → 返回 brokerIP=172.18.0.3
└─────────────────┘
│
│ 尝试连接 172.18.0.3:10911 (不可达)
↓
┌─────────────────┐
│ Broker 容器 │ 实际可访问: 宿主机IP:10911
│ IP: 172.18.0.3 │
└─────────────────┘
让 Broker 向 NameServer 注册时,使用宿主机 IP 而非容器 IP。
步骤一:创建配置文件
# 在宿主机创建配置文件
cat > /usr/local/rocketmq/broker/conf/broker.conf << 'EOF'
brokerIP1=你的宿主机IP
autoCreateTopicEnable=true
EOF
步骤二:重新部署 Broker(挂载配置文件)
# 停止并删除旧容器
docker stop mqbroker && docker rm mqbroker
# 重新运行,挂载配置文件
docker run -d --name mqbroker
-p 10911:10911 -p 10909:10909
--network rocketmq
-v /usr/local/rocketmq/broker/logs:/root/logs
-v /usr/local/rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.1.0/conf/broker.conf
-e "MAX_HEAP_SIZE=512M"
-e "HEAP_NEWSIZE=256M"
apache/rocketmq:5.1.0 sh mqbroker -n mqnamesrv:9876
-c /home/rocketmq/rocketmq-5.1.0/conf/broker.conf
验证修复:
# 查看 Console 中的 Broker 信息
# 应该看到 brokerIP1 已经显示为宿主机 IP
此时,生产者应该可以正常发送消息了!
修复了生产者超时问题后,你以为一切正常了,结果打开 Console...
Console 状态:
Console 日志:
Error connecting to Broker: Connection refused
这是一个典型的拆东墙补西墙问题:
配置 brokerIP1 前:
mqbroker:10911 访问 Broker 配置 brokerIP1 后:
mqbroker:10911,但 Broker 向 NameServer 注册的地址是宿主机 IP 网络冲突示意:
┌─────────────────┐
│ Console 容器 │ → 访问 mqbroker:10911 (容器网络)
└─────────────────┘
│
│ NameServer 返回: 宿主机IP:10911
↓
┌─────────────────┐
│ Broker 注册地址 │ = 宿主机IP:10911
└─────────────────┘
│
│ Console 尝试连接 宿主机IP:10911
↓
┌─────────────────┐
│ 网络路由问题 │ 容器内访问宿主机IP需要特殊配置
└─────────────────┘
让 Console 容器直接使用宿主机的网络栈,这样它可以通过 127.0.0.1:10911 访问 Broker(端口已映射到宿主机)。
# 停止并删除旧 Console
docker stop mqconsole && docker rm mqconsole
# 使用 host 网络模式重新部署
docker run -d --name mqconsole --network host
-e "JAVA_OPTS=-Xmx256M -Xms256M -Xmn128M
-Drocketmq.namesrv.addr=127.0.0.1:9876
-Dcom.rocketmq.sendMessageWithVIPChannel=false"
styletang/rocketmq-console-ng
为什么这样能解决问题?
使用 --network host 后:
127.0.0.1:9876 和 127.0.0.1:10911 等同于访问宿主机本地服务访问 Console:
# 不再需要端口映射,直接访问宿主机端口
# 假设 Console 默认端口是 8080
;宿主机IP>:8080
如果不使用 host 网络模式,也可以配置宿主机的路由规则,但配置较复杂:
# 启用本地路由转发
sysctl -w net.ipv4.conf.all.route_localnet=1
# 放通防火墙规则
iptables -I INPUT -d <宿主机IP> -p tcp --dport 10911 -j ACCEPT
将以下脚本保存为 deploy-rocketmq.sh,修改 BROKER_IP 为你的宿主机 IP 后执行:
#!/bin/bash
# ========== 配置区 ==========
BROKER_IP="192.168.1.100" # 修改为你的宿主机 IP
# ===========================
# 1. 创建网络
docker network create rocketmq 2>/dev/null || echo "网络已存在"
# 2. 创建目录
mkdir -p /usr/local/rocketmq/nameserver/logs
mkdir -p /usr/local/rocketmq/broker/logs
mkdir -p /usr/local/rocketmq/broker/conf
chmod 777 -R /usr/local/rocketmq/*
# 3. 创建 Broker 配置文件
cat > /usr/local/rocketmq/broker/conf/broker.conf << EOF
brokerIP1=$BROKER_IP
autoCreateTopicEnable=true
namesrvAddr=mqnamesrv:9876
EOF
# 4. 启动 NameServer
docker run -d --name mqnamesrv -p 9876:9876 --network rocketmq
-v /usr/local/rocketmq/nameserver/logs:/home/rocketmq/logs
-e "MAX_HEAP_SIZE=256M"
-e "HEAP_NEWSIZE=128M"
apache/rocketmq:5.1.0 sh mqnamesrv
# 等待 NameServer 启动
sleep 5
# 5. 启动 Broker
docker run -d --name mqbroker
-p 10911:10911 -p 10909:10909
--network rocketmq
-v /usr/local/rocketmq/broker/logs:/root/logs
-v /usr/local/rocketmq/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.1.0/conf/broker.conf
-e "MAX_HEAP_SIZE=512M"
-e "HEAP_NEWSIZE=256M"
apache/rocketmq:5.1.0 sh mqbroker -n mqnamesrv:9876
-c /home/rocketmq/rocketmq-5.1.0/conf/broker.conf
# 等待 Broker 启动
sleep 10
# 6. 启动 Console(使用 host 网络)
docker run -d --name mqconsole --network host
-e "JAVA_OPTS=-Xmx256M -Xms256M -Xmn128M
-Drocketmq.namesrv.addr=127.0.0.1:9876
-Dcom.rocketmq.sendMessageWithVIPChannel=false"
styletang/rocketmq-console-ng
echo "========== 部署完成 =========="
echo "NameServer: localhost:9876"
echo "Broker: $BROKER_IP:10911"
echo "Console: 0"
echo "============================"
# application.yml
rocketmq:
name-server: localhost:9876
producer:
group: hotel-booking-producer-group
send-message-timeout: 3000
retry-times-when-send-failed: 2
// 发送消息示例
@Service
public class OrderService {
@Autowired
private RocketMQTemplate rocketMQTemplate;
public void sendOrderMessage(Order order) {
rocketMQTemplate.syncSend(
"hotel-booking-test-topic:TEST_TAG",
order,
3000 // 超时时间 3 秒
);
}
}
# 检查容器状态
docker ps -a | grep mq
# 查看 NameServer 日志
docker logs mqnamesrv
# 查看 Broker 日志
docker logs mqbroker
# 测试生产者连接
telnet <宿主机IP> 10911
# 查看 Console 中的 Broker 状态
# 访问 ;宿主机IP>:8080,检查 "Broker" 菜单
| 组件 | 开发/测试环境 | 生产环境 |
|---|---|---|
| 部署方式 | Docker 单机 | Docker Swarm / K8s 集群 |
| NameServer | 1 个节点 | ≥3 个节点(高可用) |
| Broker | 单 Master | Master-Slave 组成集群 |
| 存储映射 | 宿主机目录 | 分布式存储 / PVC |
| JVM 内存 | 256M~512M | ≥4G(根据消息量调整) |
| 监控 | Console | Prometheus + Grafana |
| 错误信息 | 可能原因 | 解决方案 |
|---|---|---|
sendDefaultImpl call timeout | brokerIP1 配置错误 | 配置为宿主机 IP |
Connection refused | 端口未映射或防火墙拦截 | 检查 -p 参数和防火墙规则 |
| Console 无法连接 Broker | 网络模式冲突 | Console 使用 --network host |
No route info of this topic | Topic 不存在 | 启用 autoCreateTopicEnable=true |
| Broker 启动失败 | 配置文件路径错误 | 检查 -c 参数和挂载路径 |
如果使用 Docker Compose,配置更简洁:
version: '3.8'
services:
namesrv:
image: apache/rocketmq:5.1.0
container_name: mqnamesrv
ports:
- "9876:9876"
environment:
- MAX_HEAP_SIZE=256M
- HEAP_NEWSIZE=128M
networks:
- rocketmq
command: sh mqnamesrv
volumes:
- ./data/namesrv/logs:/home/rocketmq/logs
broker:
image: apache/rocketmq:5.1.0
container_name: mqbroker
ports:
- "10911:10911"
- "10909:10909"
environment:
- MAX_HEAP_SIZE=512M
- HEAP_NEWSIZE=256M
networks:
- rocketmq
command: sh mqbroker -n mqnamesrv:9876 -c /home/rocketmq/rocketmq-5.1.0/conf/broker.conf
volumes:
- ./data/broker/logs:/root/logs
- ./data/broker/conf/broker.conf:/home/rocketmq/rocketmq-5.1.0/conf/broker.conf
depends_on:
- namesrv
console:
image: styletang/rocketmq-console-ng
container_name: mqconsole
network_mode: host
environment:
- JAVA_OPTS=-Xmx256M -Xms256M -Xmn128M -Drocketmq.namesrv.addr=127.0.0.1:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false
depends_on:
- namesrv
- broker
networks:
rocketmq:
driver: bridge
启动:
# 确保 broker.conf 中的 brokerIP1 已配置
docker-compose up -d
通过本文的实战记录,我们解决了 Docker 部署 RocketMQ 时的两个核心问题:
brokerIP1 让 Broker 注册宿主机 IP--network host 让 Console 直接访问宿主机网络