RabbitMQ Network Partitions的预警和处理策略
网络分区的意义
RabbitMQ的模型类似交换机模型,且采用erlang这种电信网络方面的专用语言实现。RabbitMQ集群是不能跨LAN部署(如果要WAN部署需要采用专门的插件)的,也就是基于网络情况良好的前提下运行的。
为什么RabbitMQ需要这种前提假设?这个和它本身的数据一致性复制原理有关。RabbitMQ采用的镜像队列是一种环形的逻辑结构,如下图:
RabbitMQ除了发布(Publish)消息之外,所有的其余操作都是在master上完成,之后再将有影响的操作同步到slave节点上。如果客户端连接的是slave节点,RabbitMQ机制也会先将链接路由到master节点上。比如确认(Ack)一条消息,先在A节点上,即master节点上确认,之后再转向B节点,进而是C和D节点,最后再D返回Ack之后才真正将这条消息确认,进而标记为可删除。这个种复制原理和zookeeper的quorum原理不同,它可以保证更强的数据一致性。在这种一致性模型下,如果出现网络波动或者网络延迟等,那么整个复制链的性能就会下降。就以上图为例,如果C节点网络异常,那么整个A->B->C->D->A的循环复制过程就会大受影响,整个RabbitMQ服务性能将大打折扣,所以这里就需要引入网络分区来将异常的节点排离出整个分区之外,以确保整个RabbitMQ的性能。待网络情况转好之后再将此节点加入集群之中。
网络分区的判定
RabbitMQ中与网络分区的判定相关的是net_ticktime这个参数,默认为60s。在RabbitMQ集群中的每个broker节点会每隔 net_ticktime/4 (默认15s)计一次tick(如果有任何数据被写入节点中,此节点被认为被ticked),如果在连续四次某节点都没有被ticked到,则判定此节点处于down的状态,其余节点可以将此节点剥离出当前分区。将连续四次的tick时间即为T,那么T的取值范围为 0.75*ticktime < T < 1.25*ticktime。下图可以形象的描述出这个取值范围的原因。(每个节点代表一次tick判定的timestamp,在两个临界值的情况下会有4个tick的判定)
默认情况下,在45s,日志出现
=ERROR REPORT==== -Jul-:::: ===
Mnesia('rabbit@node1'): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, 'rabbit@node2'}
当一个节点起来的时候,RabbitMQ会记录是否发生了网络分区,你可以通过WebUI进行查看;
RabbitMQ GUI上显示 Network partition detected
Mnesia reports that this RabbitMQ cluster has experienced a network partition. There is a risk of losing data. Please read RabbitMQ documentation about network partitions and the possible solutions.
或者可以通过rabbitmqctl cluster_status命令查看,如果查看到信息中的partitions那一项是空的,就想这样:
[{nodes,[{disc,['rabbit@node1', 'rabbit@node2']}]},
{running_nodes,['rabbit@node2','rabbit@node1']},
{cluster_name,<<"rabbit@node1">>},
{partitions,[]}]
然而当网络分区时,会变成这样:
[{nodes, [{disc, ['rabbit@node1','rabbit@node2']}]},
{running_nodes,['rabbit@node1']},
{cluster_name,<<"rabbit@node1">>},
{partitions, [{'rabbit@node1',['rabbit@node2']}]}]
当一个RabbitMQ集群发生网络分区时,这个集群会分成两个或者多个分区,它们各自为政,互相都认为对方分区的节点已经down,包括queues,bindings,exchanges这些信息的创建和销毁都处于自身分区内,与其它分区无关。如果原集群中配置了镜像队列,而这个镜像队列又牵涉到两个或者多个网络分区中的节点时,每一个网络分区中都会出现一个master节点,如果分区节点个数充足,也会出现新的slave节点,对于各个网络分区,彼此的队列都是相互独立的,当然也会有一些其他未知的、怪异的事情发生。当网络恢复时,网络分区的状态还是会保持,除非采取一些措施去解决他。
手动处理网络分区
为了从网络分区中恢复,首先需要挑选一个信任的分区,这个分区才有决定Mnesia内容的权限,发生在其他分区的改变将不被记录到Mnesia中而直接丢弃。手动恢复网络分区有两种思路:
1. 停止其他分区中的节点,然后重新启动这些节点。最后重启信任分区中的节点,以去除告警。
2. 关闭整个集群的节点,然后再启动每一个节点,这里需确保你启动的第一个节点在你所信任的分区之中。
停止/启动节点有两种操作方式:
1. rabbimqctl stop/ rabbitmq-server -detached
2. rabbitmqctl stop_app/ rabbitmqctl start_app
自动处理网络分区
RabbitMQ提供了4种处理网络分区的方式,在rabbitmq.config中配置cluster_partition_handling参数即可,分别为:
1. ignore
2. pause_minority
3. pause_if_all_down, [nodes], ignore|autoheal
4. autoheal
1.ignore
默认是ignore,如果不配置rabbitmq.config或者按如下配置:
[
{
rabbit, [
{cluster_partition_handling, ignore}
] }
].
ignore的配置是当网络分区的时候,RabbitMQ不会自动做任何处理,即需要手动处理。
2.pause_minority
在rabbitmq.config配置文件中配置:
[
{
rabbit, [
{cluster_partition_handling, pause_minority}
]
}
].
当发生网络分区时,集群中的节点在观察到某些节点down掉时,会自动检测其自身是否处于少数派(小于或者等于集群中一般的节点数)。少数派中的节点在分区发生时会自动关闭,当分区结束时又会启动。这里的关闭是指RabbitMQ application关闭,而Erlang VM并不关闭,这个类似于执行了rabbitmqctl stop_app命令。处于关闭的节点会每秒检测一次是否可连通到剩余集群中,如果可以则启动自身的应用,相当于执行rabbitmqctl start_app命令。
需要注意的是RabbitMQ也会关闭不是严格意义上的大多数。比如在一个集群中只有两个节点的时候并不适合采用pause-minority模式,因为由于其中任何一个节点失败而发生网络分区时,两个节点都会被关闭。当网络恢复时,有可能两个节点会自动启动恢复网络分区,也有可能还是保持关闭状态。然而如果集群中的节点远大于两个时,pause_minority模式比ignore模式更加的可靠,特别是网络分区通常是由于单个节点网络故障而脱离原有分区引起的。不过也需要考虑2v2, 3v3这种情况,可能会引起所有集群节点的关闭。这种处理方式适合集群节点数大于2个且最好为奇数的情况。
3.pause_if_all_down
在pause_if_all_down模式下,RabbitMQ会自动关闭不能和list中节点通信的节点。语法为{pause_if_all_down, [nodes], ignore|autoheal},其中[nodes]即为前面所说的list。如果一个节点与list中的所有节点都无法通信时,自关闭其自身。如果list中的所有节点都down时,其余节点如果是ok的话,也会根据这个规则去关闭其自身,此时集群中所有的节点会关闭。如果某节点能够与list中的节点恢复通信,那么会启动其自身的RabbitMQ应用,慢慢的集群可以恢复。
有两种配置如下:
[
{
rabbit, [
{cluster_partition_handling, {pause_if_all_down, ['rabbit@node1'], ignore}}
]
}
].
和:
[
{
rabbit, [
{cluster_partition_handling, {pause_if_all_down, ['rabbit@node1'], autoheal}}
]
}
].
为什么这里会有ignore和autoheal两种不同的配置,考虑这样一种情况:有两个节点node1和node2在机架A上,node3和node4在机架B上,此时机架A和机架B的通信出现异常,如果此时使用pause-minority的话会关闭所有的节点,如果此时采用pause-if-all-down,list中配置成[‘node1’, ‘node3’]的话,集群中的4个节点都不会关闭,但是会形成两个分区,此时就需要ignore或者autoheal来指引如何处理此种分区的情形。
4.autoheal
在autoheal模式下,当认为发生网络分区时,RabbitMQ会自动决定一个获胜的(winning)分区,然后重启不在这个分区中的节点以恢复网络分区。一个获胜的分区是指客户端连接最多的一个分区。如果产生一个平局,既有两个或者多个分区的客户端连接数一样多,那么节点数最多的一个分区就是获胜的分区。如果此时节点数也一样多,将会以一种特殊的方式来挑选获胜分区。
配置示例如下:
[
{
rabbit, [
{cluster_partition_handling, autoheal}
]
}
].
RabbitMQ Network Partitions的预警和处理策略的更多相关文章
- RabbitMQ Network Partitions
Clustering and Network Partitions RabbitMQ clusters do not tolerate network partitions well. If you ...
- RabbitMQ Network Partitions 处理策略
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 网络分区的意义 RabbitMQ的模型 ...
- rabbitmq之partitions
集群为了保证数据一致性,在同步数据的同时也会通过节点之间的心跳通信来保证对方存活.那如果集群节点通信异常会发生什么,系统如何保障正常提供服务,使用何种策略回复呢? rabbitmq提供的处理脑裂的方法 ...
- RabbitMQ脑裂问题解决方案调查
现象: RabbitMQ GUI上显示 Network partition detectedMnesia reports that this RabbitMQ cluster has experien ...
- Centos6.9下RabbitMQ集群部署记录
之前简单介绍了CentOS下单机部署RabbltMQ环境的操作记录,下面详细说下RabbitMQ集群知识,RabbitMQ是用erlang开发的,集群非常方便,因为erlang天生就是一门分布式语言, ...
- RabbitMQ概念及环境搭建(四)RabbitMQ High Availability
#################################################### RabbitMQ High Availability #################### ...
- 高可用rabbitmq集群服务部署步骤
消息队列是非常基础的关键服务,为保证公司队列服务的高可用及负载均衡,现通过如下方式实现: RabbitMQ Cluster + Queue HA + Haproxy + Keepalived 3台ra ...
- RabbitMQ(四)
RabbitMQ 配置 一.RabbitMQ 配置修改方式 1.修改环境变量 2.修改配置文件(只介绍这个) 3.修改运行时参数和政策 locate rabbitmq vi /var/log/rabb ...
- RabbitMQ配置文件
配置文件Config 在Web的可视化管理界面中可以看到一些文件的路径 比如 Config文件的地址 数据库存放的文件夹 log文件的地址 进入到这个文件夹会发现有这些文件,其中example是con ...
随机推荐
- obj-c编程10:Foundation库中类的使用(3)[文件管理]
好吧,不管神马系统都无可避免的要说到文件,目录,路径(PATH)管理的内容,下面我们来看看在F库中对他们的支持.我简单看了下,不谈其他光从方法命名来说就多少显得有点复杂,如果和ruby相比就呵呵了. ...
- 恶补web之八:jQuery(2)
jquery中非常重要的部分,就是操作dom的能力: text() - 设置或返回所选元素的文本内容 html() - 设置或返回所选元素的内容(包括html标记) val() - 设置或返回表单字段 ...
- mysql基础优化-explain的使用-mysql死锁
MySQL的优化 主要包括三个方面,首先是SQL语句的优化,其次是表结构的优化(这里主要指索引的优化),最后是服务器配置的优化. 一.SQL语句的优化 在 where 及 order by 涉及的列上 ...
- 2018 ACM-ICPC World Finals B.Comma Sprinkler
WF里面最简答一题,就是一个dfs就可以了,已经访问过的点可以不再访问 #include <algorithm> #include <cmath> #include <c ...
- angular4 ionic3 app
对于angular系列来说,从2到4仅仅是版本号的变更,绝大部分都是兼容的. 如果按照规范编写代码,一般来说是没有问题的. 学习angular4 快速入门参考 https://www.an ...
- java main方法执行sql语句
public static void main(String[] args) throws Exception{ String driver = "oracle.jdbc.driver.Or ...
- Tomcat启动时加载数据到缓存---web.xml中listener加载顺序(优先初始化Spring IOC容器)
JavaWebSpringTomcatCache 最近用到在Tomcat服务器启动时自动加载数据到缓存,这就需要创建一个自定义的缓存监听器并实现ServletContextListener接口,并且 ...
- JeeSite中Excel导入导出
在各种管理系统中,数据的导入导出是经常用到的功能,通常导入导出以Excel.CSV格式居多.如果是学习的过程中,最好是自己实现数据导入与导出的功能,然而在项目中,还是调用现成的功能比较好.近期一直使用 ...
- [更新]单线程的JS引擎与 Event Loop
先来思考一个问题,JS 是单线程的还是多线程的?如果是单线程,为什么JavaScript能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO ...
- HP 3par多路径安装方法
一.Linux下multipath介绍,需要以下工具包: 在CentOS 5中,最小安装系统时multipath已经被安装,查看multipath是否安装如下: 1.device-mapper-mul ...