RabbitMQ 集群的稳定性高度依赖节点之间的网络通信质量。当你在日志中看到 network partition detected 这样的记录时,说明集群内至少两个节点之间在心跳检测周期内无法互相感知,RabbitMQ 的分区处理器(partition handler)已经介入并标记了分区状态。这条日志看起来只是一句提示,但它背后可能隐藏着网络故障、机器负载过高、配置不当等多种问题。本文围绕这条日志展开,先解释它的触发原理,再给出系统性的排查方法。

一、network partition detected 是怎么触发的
要理解这条日志,首先要知道 RabbitMQ 节点间通信基于 Erlang/OTP 的分布式机制。每个节点会通过 Erlang 的心跳机制(tick)持续向对端发送探测信号。默认配置下,net_ticktime 的值是 60 秒,系统会将这个时间划分为 4 个区间,即大约每 15 秒发送一次 tick。如果连续 4 次 tick 都没有收到对端的回应,Erlang 运行时就判定对端节点“失联”,这个时间总计约 60 秒。
一旦 Erlang 层判定节点失联,RabbitMQ 的分区检测进程会进一步确认这是真正的网络分区还是节点宕机。判定为分区后,节点会记录类似下面的日志:
2024-06-01 10:23:45.123 [error] <0.356.0> ** Node rabbit@node2 not responding ** ** RabbitMQ is running in a network partitioned cluster **
需要注意的一点是,Erlang 的心跳检测是双向的。A 节点认为 B 失联,不代表 B 也认为 A 失联,可能出现单边误判的情况。这也是很多运维人员困惑的来源:明明两台机器互相 ping 都通,日志里却报了分区。因为 tick 丢失除了物理断网,还可能是节点 GC 停顿、CPU 打满、端口被防火墙拦截等软性原因。
二、常见的分区原因分类
排查之前先对原因做个分类,可以大幅缩小排查范围。实际生产中造成网络分区的原因大致可以归为四类。
第一类是物理网络问题,包括交换机故障、网线松动、网卡损坏、机房之间专线抖动等。这类问题通常伴随大量节点同时报错,特征比较明显。第二类是节点资源问题,比如 CPU 长期 100%、内存换页严重、Erlang 进程调度被阻塞。节点太忙来不及处理 tick,就会被对端误判为失联。第三类是配置问题,比如 net_ticktime 设置得过小,网络稍有波动就触发分区;或者防火墙只放行了 5672 端口,却没有放行 Erlang 节点间通信所需的 4369(epmd)和 25672(分布式端口)。第四类是运维操作引发,例如在网卡上做变更、重启网络服务、节点频繁假死被强制 kill 后又拉起,都可能触发短暂的分区。
一个容易忽视的场景是跨机房的集群部署。两个机房之间延迟本身就有几十毫秒,如果再加上网络高峰期的丢包,tick 很容易超时。这种架构下出现间歇性分区告警,多数不是故障,而是网络质量撑不住当前配置。
三、系统化的排查步骤
拿到告警后,建议按以下顺序逐步排查,从现象到根因。
第一步,确认分区的当前状态。登录任意节点执行:
rabbitmqctl cluster_status
在输出的 Partitions 段落中,如果看到节点名后面列出了对端节点,说明分区当前仍然存在;如果为空,说明分区已经恢复,只是历史上发生过。再配合 rabbitmq-diagnostics node_health_check 和 rabbitmq-diagnostics environment | grep net_ticktime 可以确认健康状态与心跳配置。
第二步,检查网络连通性。用 ping 测试基础连通只是第一步,更重要的是确认端口层面的可达性:
# 检查 epmd 端口和分布式端口 telnet node2 4369 telnet node2 25672 # 检查网络延迟和丢包 ping -c 100 node2
如果 ping 正常但 telnet 不通,基本可以确定是防火墙或安全组问题。如果 ping 的丢包率超过 1%,或者延迟抖动很大,就要往网络质量方向排查,可以联系网络组抓包确认。
第三步,检查节点自身负载。用 top 或 vmstat 观察 CPU 和内存,重点关注是否出现持续的 CPU 饱和。同时查看 RabbitMQ 自身的监控指标:
rabbitmq-diagnostics node_status rabbitmqctl status | grep -A 5 "Memory"
如果节点内存触发了 high watermark,RabbitMQ 会阻塞客户端连接,但一般不会直接阻塞 Erlang tick。真正危险的是 Erlang VM 整体卡顿,比如大量消息积压导致调度器繁忙,这种情况在日志里往往伴随 VM memory high watermark set 或者长时间的 GC 记录。
第四步,复盘日志时间线。把所有节点的日志按时间对齐,看分区开始和结束的精确时间点,再与机器的系统日志(如 /var/log/messages 中的网卡 up/down 记录)、交换机告警做交叉比对,往往能直接锁定根因。
四、恢复集群与后续优化
分区恢复的关键原则是:以数据完整的一侧为准,让其他节点重新加入。如果分区仍在持续,需要人工介入。假设 node1 上保留着更完整的数据,则应在 node2 上停止应用并执行:
# 在被丢弃的节点上执行 rabbitmqctl stop_app rabbitmqctl reset rabbitmqctl join_cluster rabbit@node1 rabbitmqctl start_app
不要简单粗暴地重启“少数派”节点而不做 reset,这样分区可能反复出现。另外要注意 cluster_partition_handling 配置:默认是 ignore,即分区时不做任何处理继续运行,这在镜像队列场景下可能导致脑裂和数据不一致。生产环境更推荐设置为 pause_minority,让少数派一侧自动暂停,避免两侧同时接受写入。
后续优化方面,有几个建议值得落实。一是合理调整 net_ticktime,跨机房或网络质量一般的环境可以调大到 120 秒,降低误判概率:
# 在 rabbitmq.conf 中配置(单位秒) cluster_partition_handling = pause_minority # net_ticktime 需要通过环境变量设置 # RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS="-kernel net_ticktime 120"
二是如果还在使用经典镜像队列,建议逐步迁移到仲裁队列(Quorum Queue)。仲裁队列基于 Raft 协议,对分区的容忍性和一致性保障都比镜像队列好得多。三是完善监控,对分区事件、节点间延迟、Erlang 进程数等指标设置告警,做到问题发生前有预警、发生后有据可查。最后,尽量避免跨机房组建 RabbitMQ 集群,如果业务确实需要跨机房容灾,考虑使用 Federation 或 Shovel 这类松耦合的异地方案代替原生集群。
RabbitMQnetwork partition日志排查修改时间:2026-09-08 19:29:04