《RabbitMQ实战指南》整理(七)网络分区

一、网络分区的意义

当一个集群发生网络分区时,集群会分为两个部分或者更多,它们各自为政,互相都认为对方分区内的节点已经挂了,包括队列、交换器及绑定等元数据的创建和销毁都处于自身分区内,与其他分区无关。分区的引入是为了配合RabbitMQ的数据一致性复制原理。一般情况下,网络分区都是由于单个节点的故障引起的,且通常会形成一个大分区和一个单节点分区,如果配置了镜像,那么可以在不影响服务可用性的情况下从网络分区的情形下得以恢复。

二、网络分区的判定

RabbitMQ集群内两两节点之间会有信息交互,如果某节点出现网络故障或是端口不同,则会使与此节点的交互出现中断,经过超时判定后,会判定网络分区。网络分区的判断与net_ticktime参数息息相关,其默认值为60。集群内部每个节点间会每隔四分之一net_ticktime记一次应答,如果任何数据被写入节点中,则此节点会被认为已经被应答了,如果连续4此没有应答,则会判定此节点已下线,其余节点可以将此节点剥离出当前分区。

网络分区的一些细节会存储在Mnesia数据库中,当Mnesia认定发生了网络分区,则会被记录在RabbitMQ服务日志中。除了服务日志外还有以下三种方法可以判定是否出现了网络分区:

  • 通过rabbitmqctl工具查看,即采用rabbitmqctl cluster_status命令可以看到集群相关的信息,如果partitions项中有相关的内容,则说明出现了网络分区;
  • 通过Web管理页面的方式进行查看,网络分区出现时会出现告警信息;
  • 通过Http API的方式调取节点信息来检查是否发生网络分区,/api/nodes接口会返回一个Josn字符串,若其中出现partitions相关内容则表示出现了网络分区

三、网络分区的影响

1、未配置镜像

对于未配置镜像的集群,网络分区发生之后,队列也会随着宿主节点而分散在各自的分区中。对于消息发送方而言,可以成功发送消息,但是会有路由失败的情况,需要配合mandatory等机制保障消息的可靠性,对于消息消费方而言,可能会出现不可预知的现象,比如已消费消息ack会失效。网络分区发生后,客户端与某分区重新建立通信链路,其分区中如果没有相应的队列进程,则会有异常报出。如果从网络分区中恢复,数据不会丢失,但是客户端会重复消费

2、已配置镜像

网络分区的发生会引起消息的丢失,解决办法为消息发送端需要具备Basic.Return的能力,其次在检测到网络分区之后,需要迅速地挂起所有生产者进程,之后连接分区中的每个节点消费分区中所有的队列数据,在消费完之后再处理网络分区,最后从网络分区中恢复之后再恢复生产者进程。整个过程可以最大程度上保证网络分区之后的消息的可靠性。需要注意的是整个过程中会有大量的消息重复,消费客户端需要做好相应的幂等性处理。也可以将所有旧集群资源迁移到新集群来解决这个问题。

四、手动处理网络分区

为了从网络分区中恢复,需要挑选一个信任分区,该分区具有决定Mnesia内容的权限,发生在其它分区的改变将不会被记录到Mnesia中而被丢弃。挑选完后重启非信任分区中的节点,如果还有网络分区的告警,紧接着重启信任分区中的节点。这个有三个要点需要注意:

  • 挑选信任分区:可以按下面几个指标进行-分区中要有disc节点,分区中的节点数最多,分区中队列数量最多,分区中客户端连接数最多。先后顺序从前往后
  • 重启方式:重启方式有两种,rabbitmqctl stop闭和rabbitmq-server -detached命令启动;rabbitmqctl stop_app关闭和rabbitmqctl start_app命令启动。第一种方式需要同时启动Erlang虚拟机和RabbitMQ,第二种只重启RabbitMQ应用,两种方式都可以从网络分区中恢复,但是更加推荐第二种
  • 重启顺序:有两种方式,选择一种即可,第一种是停止其它非信任分区中的所有节点,然后重启这些节点,如果还有网络分区告警则再重启信任分区中的节点以去除告警;第二种是关闭整个集群中的节点,然后再启动每一个节点,需要确保启动的第一个节点在信任分区中。在决定重启顺序之前,还需要考虑master节点存在的转移现象。如果之前配置了镜像队列,可以在重启前先删除镜像队列,一定程度上阻止队列的”漂移“

五、自动处理网络分区

RabbitMQ提供了三种自动处理网络分区的方法:pause-minority模式,pause-if-all-down模式和autoheal模式,默认是ignore,即不自动处理网络分区,其修改对应config文件中的cluster_partition_handling属性

1、pause-minority模式

在此模式下,当发生网络分区时,集群中的节点在观察到某些节点下线时,会自动检测其是否属于少数派(分区中的节点小于等于集群中一般的节点数),RabbitMQ会自动关闭这些节点的运作,以满足可用性,当分区结束时又会启动。处于关闭的节点会每秒检测一次是否可以连通到剩余集群中,如果可以则启动自身的应用。

RabbitMQ也会关闭不是严格意义上的大多数,如果集群中只有两个节点,其中任一节点关闭,另一个节点都会被关闭,所以pause-minority模式适用于集群节点数大于2个的时候。但如果出现2v2、3v3类的对等节点数的分区情况,所有节点上的RabbitMQ应用都会被关闭

2、pause-if-all-down模式

该模式下,RabbitMQ集群中的节点在所配置的列表中的任何节点都不能交互时则会关闭。该模式下有两种配置,ignore和autoheal,当出现对等节点数分区的情况,ignore不会自动处理,autoheal则可以处理这种情形

3、autoheal模式

在该模式下,RabbitMQ会自动决定一个获胜的分区,然后重启不在这个分区中的节点来从网络分区中恢复。获胜分区是指客户端连接最多的分区,如果连接客户端相同则选择节点数较多的一个分区,如果节点数相同,则以节点名称的字典顺序来判断。该模式在判定出节点下线时不做动作,要等到网络分区恢复时,在判定出网络分区之后才会有相应的动作,即重启非获胜分区中的节点。

需要注意,在此模式下,如果集群中有节点处于非运行状态,那么当发生网络分区时,将不会有任何自动处理的动作

4、挑选哪种模式

ignore:网络分区发生时,不做任何动作,需要人工处理;

pause-minority:对等分区的处理不够优雅,一般用于非跨机架、奇数节点数的集群中;

pause-if-all-down模式:对于受信任节点的选择较为考究

autoheal:可以应对各个情形下的网络分区,但是如果集群中有节点处于非运行状态,则此模式会失效

posted @ 2021-02-06 20:10  Jscroop  阅读(857)  评论(0编辑  收藏  举报
//小火箭