网络分区是集群最危险的故障。4.3.6 用 Khepri 存元数据、quorum 队列用 Raft,分区时到底哪一边还能工作?cluster_partition_handling 还有用吗?愈合后要人工处理吗?这篇真的把一个节点隔离出去观察。
$ 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 上的观察,没有进一步查源码确认原因。