在 Windows Docker 上搭建 RocketMQ 单节点集群并解决常见连接与发送问题的实战经验分享

作者前言:本文基于笔者在 Windows 环境下使用 Docker 搭建 Apache RocketMQ 4.4.0 的个人实践经验撰写。RocketMQ 作为一款优秀的分布式消息队列中间件,在高并发、低延迟场景下表现出色,但其在 Docker 容器化部署中的网络配置往往会让初学者感到困惑。本文并非官方教程,仅记录了笔者从环境准备到问题解决的全过程,旨在为遇到类似问题的朋友提供参考。如果文中有所疏漏或不准确之处,欢迎读者指正。感谢 RocketMQ 社区和相关博客的启发(如 CSDN 上关于多网卡 IP 配置的文章),让我们共同学习。


1. 引言:为什么选择 RocketMQ?

Apache RocketMQ 是一款由阿里巴巴开源并捐献给 Apache 基金会的分布式消息队列,支持高吞吐、低延迟、可靠的消息传递,适用于微服务解耦、事件驱动架构等场景。在本地开发测试时,使用 Docker 快速搭建单节点集群是最便捷的方式。然而,在 Windows 平台下,Docker 的虚拟网络适配器(如 vEthernet)和多网卡环境容易导致 Broker 注册 IP 不一致、客户端连接超时等问题。

本文聚焦于:

  • Windows Docker 环境下的 RocketMQ 部署。

  • 解决 Dashboard 连接失败、Java 客户端发送状态为 SLAVE_NOT_AVAILABLE 等常见坑。

  • 通过日志分析和配置调整,实现完整链路验证。

环境版本:

  • OS: Windows 10(带 Docker Desktop)。

  • Docker: 最新版(启用 WSL 2 后端)。

  • RocketMQ: 4.4.0(镜像 rocketmqinc/rocketmq)。

  • Dashboard: apacherocketmq/rocketmq-dashboard:latest。

  • Java 客户端: rocketmq-client 4.4.0。


2. 环境准备

2.1 安装 Docker Desktop

  • 下载并安装 Docker Desktop(官网:https://www.docker.com/products/docker-desktop)。

  • 启用 WSL 2 后端(设置 > General > Use the WSL 2 based engine)。

  • 创建自定义网络:docker network create rocketmq(用于容器间通信)。

2.2 准备配置文件和目录

在宿主机创建目录,例如 D:/04-ProgramFiles/Docker/rocketmq/

  • conf/broker.conf:Broker 配置(详见后文)。

  • data/logsdata/store:持久化日志和消息存储(避免容器重启数据丢失)。

2.3 查看宿主机网络适配器

运行 ipconfig 获取 IP:

  • 重点关注 vEthernet (Default Switch) 的 IPv4(如 172.26.16.1),这是 Docker 容器访问宿主机的桥接 IP。

  • 其他如物理网卡(172.20.x.x)或 VMware 虚拟网卡(192.168.x.x)可能干扰,需避免。


3. 部署步骤

3.1 启动 NameServer

NameServer 是 RocketMQ 的注册中心。

docker run -d --network rocketmq --name rmqnamesrv -p 9876:9876 rocketmqinc/rocketmq sh mqnamesrv
  • 检查日志:docker logs rmqnamesrv(应无错误)。

3.2 配置并启动 Broker

broker.conf 内容(关键配置,后文解释):

brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 72
brokerRole = SYNC_MASTER # 单节点推荐 SYNC_MASTER,避免 SLAVE_NOT_AVAILABLE
flushDiskType = ASYNC_FLUSH
autoCreateTopicEnable = true
namesrvAddr = rmqnamesrv:9876
brokerIP1 = 172.26.16.1 # 宿主机 Docker Default Switch IP,用于注册和客户端访问
brokerIP2 = 172.26.16.1 # 用于主从复制通道(即使单节点,也可强化 HA 检查)

启动命令:

docker run -d -p 10909:10909 -p 10911:10911 --network rocketmq --name rmqbroker \
-v D:/04-ProgramFiles/Docker/rocketmq/data/logs:/opt/rocketmq-4.4.0/log \
-v D:/04-ProgramFiles/Docker/rocketmq/data/store:/opt/rocketmq-4.4.0/store \
-v D:/04-ProgramFiles/Docker/rocketmq/conf/broker.conf:/opt/rocketmq-4.4.0/conf/broker.conf \
-e "NAMESRV_ADDR=rmqnamesrv:9876" rocketmqinc/rocketmq sh mqbroker -c /opt/rocketmq-4.4.0/conf/broker.conf
  • 日志检查:docker logs rmqbroker 应显示 "The broker[...] boot success",并指定 brokerIP1。

3.3 启动 Dashboard

Dashboard 用于可视化监控。

docker run -d --network rocketmq --name rmq-dashboard -p 8080:8082 \
-e "NAMESRV_ADDR=rmqnamesrv:9876" apacherocketmq/rocketmq-dashboard:latest

3.4 验证集群

  • mqadmin 工具(从 rocketmq-all-4.4.0-bin-release 下载,进入 bin 目录):

    mqadmin clusterList -n 127.0.0.1:9876

    输出应显示 broker-a Addr 为 172.26.16.1:10911。

  • Dashboard:Cluster 页面显示 Broker 信息。


4. 常见问题及解决方案

4.1 Dashboard 显示 "connect to null failed" 或 Broker 未注册

原因:Broker 默认使用容器内部 IP(127.0.0.1 或 172.18.x.x)注册到 NameServer,导致 Dashboard(同网络)无法路由。 解决方案

  • 设置 brokerIP1 为宿主机 Docker Default Switch IP(通过 ipconfig 获取)。

  • 重启 Broker,观察日志确认注册 IP。

  • 备选:如果失败,尝试物理网卡 IP,但优先 Default Switch(Docker 桥接优化)。

4.2 Java 客户端连接超时或路由为 127.0.0.1

客户端代码示例(Spring Boot 测试):

DefaultMQProducer producer = new DefaultMQProducer("test-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.setVipChannelEnabled(false);  // 禁用 VIP 通道,避免 10909 端口问题
producer.start();
Message msg = new Message("testTopic", "Hello RocketMQ!".getBytes());
SendResult result = producer.send(msg);
System.out.println("发送状态: " + result.getSendStatus());
producer.shutdown();

原因:路由 IP 不一致。 解决方案

  • 确保 Broker brokerIP1 正确。

  • 添加 producer.setVipChannelEnabled(false) 和路由打印:

    List<MessageQueue> queues = producer.fetchPublishMessageQueues("testTopic");
    System.out.println("路由: " + queues);
  • JVM 参数:-Djava.net.preferIPv4Stack=true 避免 IPv6 干扰。

4.3 发送状态 SLAVE_NOT_AVAILABLE

原因

  • 默认 ASYNC_MASTER 模式下,客户端检查 Slave 可用性。即使单节点,无 Slave 也会返回此警告(参考:博客)。

  • 即使消息已写入(Dashboard Produce Count +1),状态仍降级。 解决方案

  • 单节点时切换 brokerRole = SYNC_MASTER(同步模式跳过 Slave 检查)。

  • 设置 brokerIP2 与 brokerIP1 一致,确保 HA 复制通道 IP 统一(参考:博客))。

4.4 Dashboard Broker NO. 显示 0(undefined)

原因:Dashboard 解析心跳时角色标签不明确(版本兼容)。 解决方案:忽略(不影响功能),或重启后等待心跳刷新;mqadmin clusterList 可确认 "Master" 角色。

5. 全链路验证:生产消费测试

  • 生产者:如上代码,状态 SEND_OK。

  • 消费者

DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test-consumer-group");
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.subscribe("testTopic", "*");
consumer.registerMessageListener((msgs, context) -> {
   System.out.println("收到: " + new String(msgs.get(0).getBody()));
   return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
consumer.start();
Thread.sleep(30000);
consumer.shutdown();
  • Dashboard:观察 TPS 和 Count 变化。


7. 总结与注意事项

通过上述步骤,您可以在 Windows Docker 上快速搭建 RocketMQ 并解决网络相关痛点。关键在于理解 Docker 桥接 IP 和 RocketMQ 的注册/复制机制。生产环境建议:

感谢阅读!如果本文帮到您,欢迎点赞分享。笔者水平有限,实践中有任何疑问,评论区交流。

  • 微信
  • 赶快加我聊天吧
  • QQ
  • 赶快加我聊天吧
  • weinxin
三桂

发表评论 取消回复 您未登录,登录后才能评论,前往登录