文章目录
-
- [一、 为什么会出现"双网卡问题"?](#一、 为什么会出现“双网卡问题”?)
-
- [关键冲突点:Broker 汇报了错误的"身份证"](#关键冲突点:Broker 汇报了错误的“身份证”)
- [二、 核心症状(怎么判断自己踩坑了?)](#二、 核心症状(怎么判断自己踩坑了?))
- [三、 完美解决方案](#三、 完美解决方案)
-
- [方案 A:如果是原生安装(修改 `broker.conf`)](#方案 A:如果是原生安装(修改
broker.conf)) - [方案 B:如果是 Docker / Docker Compose 安装(最推荐)](#方案 B:如果是 Docker / Docker Compose 安装(最推荐))
- [方案 A:如果是原生安装(修改 `broker.conf`)](#方案 A:如果是原生安装(修改
- [四、 必须要放行的"云服务器安全组"端口](#四、 必须要放行的“云服务器安全组”端口)
在分布式中间件(如 RocketMQ、Kafka 等)的部署中,"双网卡问题" (或者叫内外网隔离、多网络接口问题)是把中间件部署在远端云服务器,而本地 Spring Boot 去连接时最经典、最容易让人抓狂的坑。
它的核心表现通常是:明明 Nacos 能连上,RocketMQ 的 Namesrv 也能连上,但一发送消息或者消费消息就直接报超时(Timeout)或连接拒绝(Connection Refused)。
下面我们用最通俗的语言,彻底拆解这个问题的底层原理和解决方案。
一、 为什么会出现"双网卡问题"?
在阿里云等云服务器(ECS)上,通常存在两块"虚拟网卡":
- 内网网卡(Private IP): 比如
172.19.xx.xx。这是云厂商机房内部通信用的,速度极快(内网千兆/万兆),且不花流量费。 - 公网网卡(Public IP): 比如
47.98.xx.xx。这是暴露给互联网的,你本地电脑连接服务器、以及用户访问网站都走这个 IP。
关键冲突点:Broker 汇报了错误的"身份证"
RocketMQ 的架构是:NameServer(注册中心) 负责管理路由,Broker(数据节点) 负责真正存取消息。
- 默认情况: 当你在云服务器上启动 RocketMQ Broker 时,它默认会去抓取服务器的内网 IP(因为在服务器看来,内网网卡才是它的主网卡)。
- 注册阶段: Broker 向 NameServer 报到,说:"我叫 Broker-A,我的地址是
172.19.xx.xx:10911。" - 本地连接: 你本地的 Spring Boot 启动了,配置了 NameServer 的公网 IP (
47.98.xx.xx)。连接成功! - 死锁发生: Spring Boot 问 NameServer:"我要发消息,请问 Broker 在哪?" NameServer 极为诚实地把刚才 Broker 注册的地址丢给本地:"Broker 在
172.19.xx.xx:10911,你去吧。" - 崩溃: 你的本地电脑在互联网上,怎么可能直接访问到阿里云机房内部的
172.19.xx.xx呢?于是,本地 Spring Boot 开始疯狂尝试连接这个内网 IP,直到连接超时报错。
二、 核心症状(怎么判断自己踩坑了?)
如果你遇到以下现象,99% 就是双网卡/内外网路由问题:
- 测试连接正常: 用
telnet 47.98.xx.xx 9876(NameServer 端口)是通的。 - 控制台正常: 部署在同台服务器上的 RocketMQ Dashboard(控制台)能正常看到集群和 Topic。
- 唯独本地代码报错: 本地 Spring Boot 生产者发送消息时,日志卡住,几秒后抛出
RemotingConnectException: connect to <172.19.xx.xx:10911> failed。注意看报错信息里的 IP,如果变成了服务器的内网 IP,就是此问题。
三、 完美解决方案
解决这个问题的核心逻辑非常简单:强行指定 Broker 对外宣布的"身份证"为公网 IP。
针对你使用 Docker 或 原生安装,修改方式略有不同:
方案 A:如果是原生安装(修改 broker.conf)
找到你 RocketMQ 的配置文件(通常在 conf/2m-2s-async/ 或自定义路径下的 broker.conf),在文件末尾显式添加一行配置:
properties
# 关键配置:强行指定 Broker 对外暴露的 IP 为你的云服务器公网 IP
brokerIP1 = 47.98.xx.xx
# 如果你要做主从,或者有特殊监听需求,可以把 brokerIP2 也配上,一般配 brokerIP1 即可
# brokerIP2 = 47.98.xx.xx
注意:启动 Broker 的时候,必须带上 -c 参数指定这个配置文件,否则配置不生效:
bash
nohup sh mqbroker -n localhost:9876 -c ../conf/broker.conf &
方案 B:如果是 Docker / Docker Compose 安装(最推荐)
如果你是用 Docker 部署的,由于 Docker 容器内部还有一套虚拟网络,更容易触发这个问题(Broker 会把 Docker 的容器内网 IP 如 172.17.0.x 注册过去)。
在 Docker 启动命令中,通过 -c 或者环境变量将 brokerIP1 传进去。
Docker Run 示例:
bash
docker run -d \
--name rmqbroker \
-p 10911:10911 -p 10909:10909 \
vincenzopalazzo/rocketmq:v5.1.0 \
sh mqbroker -n 47.98.xx.xx:9876 -c /opt/rocketmq/conf/broker.conf --param "brokerIP1=47.98.xx.xx"
Docker Compose 示例(最直观):
在映射的 broker.conf 挂载文件中写死 brokerIP1=你的公网IP,或者在 command 启动命令中注入:
yaml
version: '3.5'
services:
rmqnamesrv:
image: apache/rocketmq:5.1.0
container_name: rmqnamesrv
ports:
- 9876:9876
command: sh mqnamesrv
rmqbroker:
image: apache/rocketmq:5.1.0
container_name: rmqbroker
ports:
- 10909:10909
- 10911:10911
environment:
- NAMESRV_ADDR=rmqnamesrv:9876
# 核心就在最后这一句,强行指定当前 Broker 注册上去的 IP 是公网公网 IP
command: sh mqbroker -c /home/rocketmq/rocketmq-5.1.0/conf/broker.conf --param "brokerIP1=47.98.xx.xx"
depends_on:
- rmqnamesrv
四、 必须要放行的"云服务器安全组"端口
改完配置后,本地要成功通信,还需要在阿里云/腾讯云后台放行以下几个端口。RocketMQ 用的端口比普通中间件多,少放一个都会失败:
9876: NameServer 的端口(本地 Spring Boot 建立初步连接、拉取路由表用)。10911: Broker 的默认监听端口(本地非 VIP 通道发送/消费消息的核心通道)。10909: Broker 的 VIP 通道 端口(RocketMQ 默认开启 VIP 通道,如果你的客户端没显式关闭 VIP 通道,消息会往这个端口发。很多人只放行了 10911 没放行 10909,结果依然超时)。8080/8081(针对 RocketMQ 5.x 纯 gRPC 模式): 如果你使用的是最新的 RocketMQ 5.x 并且使用了新的 Proxy 模式,走的是 gRPC 协议,需要开放对应的 Proxy 端口(默认 8081)。
总结口诀
本地连远端,Broker 别偷懒;
莫报内网号,公网 IP 填上面(brokerIP1);
九八七六连名字,一零九一送消息;
还有一零九零九,安全组里别漏失!