目录
step3:嘚瑟一下,elasticSearch 如何解决脑裂
step1:回答一下,什么是脑裂问题?
在一个高可用集群中,当多个服务器在指定的时间内,由于网络的原因无法互相检测到对方,而各自形成一个新的小规模集群,并且各小集群当中,会选举新的master节点,都对外提供独立的服务,
由于网络断裂的原因,一个高可用集群中,实际上分裂为多个小的集群,这种情况就称为裂脑。
也有的人称之为分区集群,或者大脑垂直分隔,互相接管对方的资源,出现多个Master的情况,都可以称为脑裂。
脑裂(Split-Brain)是一个形象的比喻,好比“大脑分裂”,也就是本来一个“大脑”被拆分了两个或多个“大脑”。
裂脑之后的后果是,可能会导致服务器端的数据不一致,或造成数据的丢失
step2:嘚瑟一下,ZooKeeper如何解决脑裂
安装ZooKeeper之前,需要规划一下节点,ZooKeeper节点数有一个重要的要求:ZooKeeper集群节点数必须是奇数。
这个要求,与ZooKeeper 的默认解决脑裂的策略有关系。
对于一个集群,想要提高这个集群的可用性,通常会采用多机房部署,
比如,为了高可用,将一个由 6 个节点的 zkServer 集群,部署在了两个机房,具体如下图:
正常情况下,此集群只会有一个 Leader,
并且 集群的Leader节点是集群通过选举的规则所有节点中选出来的,简称为选主。
那么如果机房之间, 发生断网,一个子网是3个节点,
一个大的集群, 被分割为 2个小的集群,每个小的集群各自3个节点,
选举出各自的leader,对外提供服务, 发生脑裂。
zk 如何解决脑裂问题呢?
ZooKeeper选主规则中很重要的一条是:要求“可用节点数量 > 总节点数量/2” 。
这条规则,叫做 Quorums 过半机制。
ZooKeeper集群使用了一种简单的节点数过半机制,确保集群被分裂后,还能否正常工作。
Quorums 直接翻译是 法定人数,就是通过投票的方式来,多数派才能选择 leader。ZooKeeper默认设置的是采用Majority Qunroms的方式来支持Leader选举。
过半机制就是“可用节点数量 > 总节点数量/2”,集群才能选举Leader,才是可用的,才可以对外服务;
为什么要“可用节点数量 > 总节点数量/2”呢?
在上图中,如果机房之间的网络断了之后,两个机房内的 zkServer 还是可以相互通信的,如果不考虑过半机制,那么就会出现每个机房内部都将选出一个 Leader。这就出现了 集群 脑裂(Split-Brain)。
所以,要求 “可用节点数量 > 总节点数量/2”。
但是, 在上面的例子中, 每个IDC机房,每个小的集群各自3个节点,都没有过半, 所以, 每个小集群都选举不了Leader,都不可用,当然,整个集群也不可用用。
从而, ZooKeeper集群节点数必须是基数。
发生断网之后,一定会出现一个大点的子集群和一个小的子集群。
-
小的集群里边, 选举不了leader,不能提供服务。
-
由大点的子集群, 选举一个 leader,提供服务。
比如, 集群节点只有 5个,断网之后,3个节点的小集群, 满足过半机制,还可以提供服务。
Quorums 过半机制,就是解决集群的脑裂问题的默认机制。
为啥ZooKeeper集群节点数必须是奇数呢?
从上面的例子可以看到,Quorums 过半机制 在偶数节点的场景下,发生失效,而集群节点数必须是奇数可以规避 这个问题 。
更极端的例子是: 100个节点的集群,如果网络问题导致分为两个部分,50个节点和50个节点,这样整个集群还是不可用的,因为按照Quorums的方式必须51个节点才能保证选出1个Leader。
所以,ZooKeeper集群节点数必须是奇数, 规避Quorums 在偶数场景可能导致的无效问题。
另外,节点数配置成奇数,还有一个好处:集群的容忍度更高, 节省服务器资源。
-
比如3个节点的集群,Quorums = 2, 也就是说: 集群可以容忍1个节点失效,这时候还能选举出1个lead,集群还可用.
-
比如4个节点的集群,它的Quorums = 3,Quorums要超过3,相当于集群的容忍度还是1,如果2个节点失效,那么整个集群还是无效的, 集群可以容忍的,仍然是1个节点失效,
所以:
4个节点的集群的容忍度 = 3个节点的集群的容忍度,但是4个节点的集群多了1个节点,相当于浪费了资源。
step3:嘚瑟一下,elasticSearch 如何解决脑裂
ElasticSearch 和 zookeeper集群一样,也存在脑裂问题。
不过,es 集群的leader ,改名字了,叫做 Master 节点,不叫做leader节点, 但是换汤不换药,本质是一样的。
es 集群中,候选主节点(即有资格成为主节点、master 候选人)配置为:
node.master: true
node.data: false
从节点配置为:
node.master: false
node.data: true
候选主节点参与 master 的选举。
一个高可用的Es集群,候选 master 至少需要3个,保证 master 节点的高可用。
当然,可以更多,但是正式的master的选举,同样遵守 Quorums 过半机制。
只是, ES必须手动设置 法定候选人的数量, 通过以下参数设置:
discovery.zen.minimum_master_nodes
上面的参数值,设置超过所有候选节点一半以上来解决脑裂问题,即设置为 (N/2)+1;
该参数是用于控制选举行为发生的最小集群主节点数量。
当备选主节点的个数大于等于该参数的值,且备选主节点中有该参数个节点认为主节点挂了,进行选举。
官方建议为(n/2)+1,n 为候选 master 个数(即有资格成为主节点的节点个数)
step4:再来回答redis 集群的脑裂
包括:
-
哨兵(sentinel)模式下的脑裂
-
集群(cluster)模式下的脑裂
哨兵(sentinel)模式下的脑裂
哨兵(sentinel)模式下的脑裂,主要是由于网络分区,导致 master、slave 和 sentinel 三类节点处于不同的网络分区。
此时哨兵无法感知到 master 的存在,会将 slave 提升为 master 节点。
此时就会存在两个 master,就像大脑分裂,那么原来的客户端往继续往旧的 master 写入数据,而新的master 就会丢失这些数据
下面是一个例子:
1个master与3个slave组成的哨兵模式(哨兵独立部署于其它机器),
刚开始时,2个应用服务器server1、server2都连接在master上,
如果master与slave及哨兵之间的网络发生故障,但是哨兵与slave之间通讯正常,
这时3个slave其中1个,经过哨兵投票后,提升为新master,
如果恰好此时server1仍然连接的是旧的master,而server2连接到了新的master上。
脑裂之后,会数据就不一致了,下面有两个例子:
1:基于setNX指令的分布式锁,可能会拿到相同的锁,因为这个锁,处于不同的 mater上边 ;
2:基于incr生成的全局唯一id,也可能出现重复, 因为这个id, 在不同的master上边。
集群(cluster)模式下的脑裂
cluster模式下,这种情况要更复杂,例如集群中有6组分片,每给分片节点都有1主1从,
如果出现网络分区时,各种节点之间的分区组合都有可能。
手动解决问题
在正常情况下,如果master挂了,那么写入就会失败,
如果是手动解决,那么人为会检测master以及slave的网络状况,然后视情况,
如果是master挂了,重启master,
如果是master与slave之间的连接断了,可以调试网络,
这样虽然麻烦,但是是可以保证只有一个master的,所以只要认真负责,不会出现脑裂。
自动解决问题
Redis cluter 内部中有一个故障转移机制,如果一旦发现master挂了,就在slave中选举新的master节点以实现故障自动转移。
问题,就出现在这个自动故障转移上,如果一旦大家监测不到一个master,尽管master还是在正常运行,集群也认为它挂了,会在slave中选举新的master,
而有一部分应用仍然与旧的master交互,当旧的master与新的master重新建立连接,旧的master会同步新的master中的数据,而旧的master中的数据就会丢失。
所以,自动故障转移, 在发生脑裂的之后恢复的时候,会导致老master数据的丢失
如何解决脑裂?
设置每个master限制slave的数量
redis的配置文件中,存在两个参数
min-slaves-to-write 3
min-slaves-max-lag 10
-
第一个参数表示连接到master的最少slave数量
-
第二个参数表示slave连接到master的最大延迟时间
按照上面的配置,要求至少3个slave节点,且数据复制和同步的延迟不能超过10秒,否则的话master就会拒绝写请求,
配置了这两个参数之后,如果发生集群脑裂,原先的master节点接收到客户端的写入请求会拒绝,就可以减少数据同步之后的数据丢失。
注意:较新版本的redis.conf文件中的参数变成了
min-replicas-to-write 3
min-replicas-max-lag 10
解决 redis中的异步复制情况下的数据丢失问题,也能使用这两个参数
配置这两个参数之后,如果发生集群脑裂,原先的master节点接收到写入请求就会拒绝,就会减少数据同步之后的数据丢失