分布式系统
在高可用系统中,系统一般采用分布式架构,来实现高可用的需求,即当系统中单节点故障时,其他服务可以提供同样的服务,保证系统仍然能够正常提供服务。在分布式系统中,要遵循CAP原则,即一致性,可用性,分区容忍性。通常来说,分布式系统只能满足CAP中的两个,比如zookeeper是CP的, eureka是AP的。
分布式系统采用的高可用模式也有区别,一种是无状态的高可用,也就是没有leader的角色,各服务提供的是无差别无状态的服务。单节点挂了之后,其他节点可以平替。 另外一种是有状态的高可用,常见的如mysql集群,采用主从模式,主节点提供读写能力,从节点提供读能力,高可用集群中的节点提供的能力是有差异的,主节点挂了之后需要重新选举主节点来形成新的主从集群。
脑裂问题
前一章中提到的无状态高可用集群不存在脑裂问题,而有状态的高可用集群模式是存在脑裂问题的。
那么,为什么有状态的高可用集群存在脑裂问题?
在有状态的高可用集群中,是需要选取一个节点作为leader节点的,leader节点负责commit一些任务,然后在集群内广播一些消息。 当因为网络等原因,造成集群出现了多个分区时,主节点就不能与集群内所有节点进行通信,这时一部分集群就会认为主节点服务宕机,开始进行新leader的选举,此时会在各分区内都选举出leader,整个集群内会存在多个leader,然后各leader会各自处理一些事务,这些事务没有在整个集群内同步。 当集群网络修复后,整个集群内会发现存在多个leader,并且已经各自提交了一些事务,就会造成集群内的业务混乱。就如同出现了两个大脑一样,形成了脑裂的情形。
脑裂的解决方案
根据脑裂形成的原因,可以看出脑类出现的场景:
1、集群出现了网络问题,形成了多个分区的场景。
2、没有leader的分区进行了选举,选举了新的leader
那针对以上形成脑裂的条件,可以有以下思路:
1、心跳链路高可用
集群中出现网络原因,导致的是集群内foller和leader之间的通信问题,也就是互相感知不到了对方的存在foller感知不到leader存在就会进行选举。 所以加强心跳通信的可靠性,比如通过多种方式进行心跳信息的传递,当有一条链路失效时,还有其他链路能够将心跳信息发出,避免出现多个分区。 可以考虑主动发送心跳,被动拉取心跳,通过mq发送心跳等方式,总之是通过多种方式将心跳信息发出去,避免单链路故障导致多分区出现。
2、设置合法选举数
集群在进行leader选举时,一定要达到一定的选举数才能进行有效的选举,比如zookeeper中设置要超过原集群中半数以上的节点同意才能进行有效的选举。这样及时形成了两个分区,那也只有一个分区能够选举出新的leader,并且在两个分区中的通信问题修复后,新leader具有更高的version,可以通过epoch广播来将新的leader信息同步给旧的leader。
例如:在一个3个节点的集群中,有2个节点存活就可以选举leader,另外一个节点只有1个节点,所以不具备leader选举条件,也就是只会在2个节点的集群中会产生出新的leader。
3、设置共享锁
leader在选举通过后,要尝试获取一个共享锁,也即是增加一个第三方的仲裁机制,leader选举出来之后,要同时再去获取一个共享锁,达到两个条件,才能成为一个新的leader。
但是此方法会有一个问题,当原leader挂了之后,对共享锁没有释放,这个时候是选举不出新的leader,会造成集群不可用,只能等原leader恢复才可以。