bigywater.tech
RabbitMQ · 19

网络分区处理策略

网络分区是集群最危险的故障。4.3.6 用 Khepri 存元数据、quorum 队列用 Raft,分区时到底哪一边还能工作?cluster_partition_handling 还有用吗?愈合后要人工处理吗?这篇真的把一个节点隔离出去观察。

15 秒
少数派节点声明新队列时的等待——挂起,没有返回
11 条
分区期间少数派节点本地写入的经典队列愈合后取出的条数(10 + 1),一条没丢
(none)
愈合后 Network Partitions 的内容——没有需要手工处理的分区状态

怎么隔离

实测 · 本机执行输出
  $ rabbitmqctl eval "application:get_env(rabbit, cluster_partition_handling)."  →  undefined(没有配置:不设就是 ignore 的行为)
  队列: cq1 classic n1@localhost / cq3 classic n3@localhost / qq quorum n3@localhost

把一个节点自己的 Erlang cookie 改掉并断开连接:它和其余节点都互相连不上,但进程还在运行。这比直接 kill 更接近“网络不通”,因为少数派一侧还在接受客户端连接。

多数派一侧

实测 · 本机执行输出
  从 n1@localhost 看 cluster_status: Running Nodes = ['n1@localhost', 'n2@localhost'];Network Partitions = ['(none)']
  从 n3@localhost 看 cluster_status: Running Nodes = ['n3@localhost'];Network Partitions = ['(none)']

元数据可写(新队列声明成功),quorum 队列重新选出 leader,发布成功。

少数派一侧

实测 · 本机执行输出
  多数派侧 n1:声明新队列 new.maj: 成功(0.0 s)
  少数派侧 n3:声明新队列 new.min: 15 秒内没有返回
  n3 往本地的经典队列 cq3 发布: 成功(confirm 回来)(0.0 s)
  n1 往 n1 上的经典队列 cq1 发布: 成功(confirm 回来)(0.0 s)
  n1 往 quorum 队列 qq 发布(leader 原来在 n3): 成功(confirm 回来)(0.0 s)
  n3 往 quorum 队列 qq 发布: 10 秒内没有返回
  list_queues(从 n1 看): name type leader online / new.maj classic n1@localhost / cq1 classic n1@localhost / qq quorum n2@localhost [n2@localhost, n1@localhost]

声明新队列和写 quorum 队列都会一直挂起;只靠本地数据的经典队列照常收发——这也意味着少数派一侧可能继续接收一些只存在这一侧的消息。

愈合

实测 · 本机执行输出
  愈合后从 n1@localhost 看: Running Nodes = ['n1@localhost', 'n2@localhost', 'n3@localhost'];Network Partitions = ['(none)']
  愈合后从 n3@localhost 看: Running Nodes = ['n1@localhost', 'n2@localhost', 'n3@localhost'];Network Partitions = ['(none)']
  cq3(n3 上,分区期间 n3 本地发过 1 条): 取出 11 条(10 + 1)
  cq1(n1 上): 取出 11 条
  愈合后从 n3 声明新队列 new.after: 成功(0.0 s)

网络恢复后集群自动合并,Network Partitions 为空,不需要重启节点;经典队列在分区期间收到的消息保留。

旧配置项

实测 · 本机执行输出
  $ rabbitmqctl eval "application:get_env(rabbit, cluster_partition_handling)."  →  {ok,pause_minority}
  客户端连 n1@localhost 的 AMQP 端口: 可以连接
  客户端连 n3@localhost 的 AMQP 端口: 可以连接
  n1 看 Running Nodes = ['n1@localhost', 'n2@localhost']
  愈合后客户端连 n3: 可以连接(自动恢复)

cluster_partition_handling 默认没有配置。配成 pause_minority 后,被隔离的节点在 10 秒内仍然接受 AMQP 连接,没有观察到暂停。这是在 4.3.6 上的观察,没有进一步查源码确认原因。

分步演示

网络分区
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / RabbitMQ 4.3.6 / Erlang/OTP 28.5 / pika 1.4.4(Homebrew 与临时虚拟环境);所有节点都是本机自己起的 RabbitMQ 进程(127.0.0.1,端口 9500 以上,每个实验独立的数据目录与节点名,不连任何外部服务);命令输出来自真实的 rabbitmqctl 与管理 API,发布与消费用 pika 的真实连接;计时用 time.perf_counter,数字每次运行会有小幅抖动。集群是 3 个本机节点;分区是把 n3 的 Erlang cookie 改成别的值并断开,别的节点连不上它、它也连不上别的节点(rabbitmqctl 用 --erlang-cookie 访问被隔离的 n3);愈合是改回 cookie 并重新 connect_node;挂起的操作各等 10~15 秒
    • 没有验证:真实的网络丢包 / 延迟型分区(这里是完全断开);非对称分区(A 能连 B、B 能连 C、A 连不上 C);pause_minority 与 autoheal 在更长等待时间下的行为;分区期间 quorum 队列的 leader 在少数派一侧时的消息归宿(这里 leader 在 n3,多数派侧重选了 leader,n3 侧写入挂起,愈合后挂起的发布结果没有跟踪);大消息量下愈合的追赶时间
    京ICP备2026067502号-1京公网安备11010502063487号