从k8s集群主节点数量为什么是奇数来聊聊分布式系统

作者:肥嘟嘟左卫门熊

从k8s集群主节点数量为什么是奇数来聊聊分布式系统

前言

今天简单聊一聊一个小问题,即为什么k8s的集群主节点数量通常是奇数,且3或5个居多?

我们先抛出答案

  • 2467等数量的主节点也是可以的,但是不推荐的的原因如下

1. 奇数的原因是防止资源的浪费

k8s的一致性算法RAFT,要求集群需要数量大于(n/2)的正常主节点才能提供服务(n为主节点数)

因此3个主节点有1个节点的容错率,而4个主节点也只有1个节点的容错率

2. 三个或五个也是平衡的考虑

3或5则是因为1个没有容错率,7个主节或更多将导致确定集群成员和仲裁的开销加大,不建议这样做

脑裂现象?

这是在Elasticsearch、ZooKeeper、k8s集群都会出现的现象

集群中的Master或Leader节点往往是通过选举产生的。

在网络正常的情况下,可以顺利的选举出Leader。但当两个机房之间的网络通信出现故障时,选举机制就有可能在不同的网络分区中选出两个Leader。当网络恢复时,这两个Leader该如何处理数据同步?又该听谁的?这也就出现了“脑裂”现象。

举例

某公司有机房如下

从k8s集群主节点数量为什么是奇数来聊聊分布式系统

如果当有一天电缆被挖怀了,上海的机房和昆明的机房没法连通了,会存在什么情况呢?

从k8s集群主节点数量为什么是奇数来聊聊分布式系统

情况一:原来的leader是在上海的服务器

我们假设原来的leader是在上海的服务器,那么昆明的两台服务器由于电缆被挖断,无法与leader建立连接,那么昆明的两台服务器就会认为主节点挂了,开始选举leader,2台服务器会把票投给其中的一台,2<5/2,不满足集群中存活的节点数必须要超过总节点数的半数才能继续提供服务的规定,所以昆明的机房是不能继续提供服务的。上海机房的存活数量为3台,组成了一个只有3个节点的小集群,3>5/2,所以上海的机房能继续提供服务。

情况二:原来的leader是在昆明的服务器

我们假设原来的leader是在昆明的服务器,那么上海的机房由于和leader断开,上海的机房会开始重新选举leader,上海机房的存活数量为3台,组成了一个只有3个节点的小集群,3>5/2,所以上海的机房能继续提供服务。昆明只剩下两台服务器,不满足集群中存活的节点数必须要超过总节点数的半数才能继续提供服务的规定,昆明机房是不能继续提供服务。

也就是说,即使出现两个机房网络通信断开的情况,ZK由于集群中存活的节点数必须要超过总节点数的半数才能继续提供服务这个规定,也只会有一个leader对外服务,不会出现各个机房分选出自己的leader的情况,这样就避免了脑裂(多个主节点)的问题。

我们设想一下如果没有集群中存活的节点数必须要超过总节点数的半数才能继续提供服务这个规定,当出现故障的时候就可能会存在多个leader,就会造成数据不一致,各个机房自己玩自己的,而这是很致命的。

那么为什么一定要是超过半数,不能是等于半数呢?
我们还是以上面的图来说,如果上海和昆明各有3台服务器,总数是6台服务器。两个机房网络断开的时候,如果是等于半数,就会分选出各自的leader,出现脑裂的问题。

脑裂现象总结

为了避免脑裂的问题,给出了一个规定:集群中存活的节点数必须要超过总节点数的半数才能继续提供服务,而正是由于这个规定,导致集群中n台和n+1台你的容灾能力是一样的(n为奇数),都只能坏一台。

k8s的一致性算法(consensus algorithm)

k8s使用RAFT作为它的一致性算法,使用该算法的还有etcd等。目的是实现分布式系统所需要的特性。(见下面条目分布式系统的挑战

RAFT 算法只能容错故障节点,并且最大容错节点数为(n-1)/2

分布式系统的挑战

  • 一致性
  • 时序性
  • 并发性
  • 健壮性

有哪些一致性

  • 逻辑时间的一致性:决定事件发生的顺序
  • 互斥性的一致性:访问资源的所有权
  • 协调者的共识:谁是当前的leader

为什么分布式系统需要leader?

分布式系统中很多类任务都需要单个进程(或实例或节点)扮演居中协调的协调者角色(coordinator),比如数据备份管理、组成员通信或原子性提交协议制定等,这个协调者角色就是leader或master。

选举

在RAFT算法里,有如下的概念

名词解释

  • term 任期:数字越大表示是越新的任期
  • requestVote:当node被索要投票时,如果没有投给别人就会投给索要的人

比如NodeA的term是1,向term为0的NodeB和NodeC索要投票,此时NodeB和NodeC的term会变成1,一个term内只能投票一次

  • log entry: 操作条目日志
  • appending entry:追加条目,即集群进行的操作
  • 平票情况:平票时,节点会震荡直到有一个leader产生,由于timeout是一个随机数,所以很少会出现平票

两个timeout

  • election timeout: 竞选倒计时,没有在倒计时前收到leader消息就会转为candidate
  • heartbeat timeout:leader间断性的发送心跳,表明自己正常

日志复制(log replication)

之所以需要log replication,为了即使leader挂了,剩下的node也可以恢复日志,是一个容错机制

日志复制过程

  1. 系统的所有更改现在都通过领导者,每次更改都在节点日志中的添加记录
  2. 客户端发送一个变更请求
  3. 该日志记录当前没有提交,所以不会更新节点的值。
  4. 要提交记录,节点首先将其复制到follower节点...
  5. 然后leader等待,直到大多数节点都记完了这条记录
  6. leader得到反馈后,记录已commit到领导者节点上,并且节点状态为“ 5 ”
  7. 然后领导者通知跟随者该记录已commit
  8. 现在,集群已就系统状态达成共识

要求节点数大于2n的原因

当一个请求进入时,leader会同步到所有node,当大多数node认可时,才会执行commit

所以当5个节点因网络问题被为2和3时,由于2个节点的集群无法得到大多数节点的认可,因此无法commit

而如果3集群选举出了新节点,那么可以继续提供服务,网络问题修复后,由于3是新选举出的节点,因此3的term更高,2节点会被同步3节点的信息

参考资料

  1. 可视化raft
  2. 易于理解的分布式共识算法,Raft! | 神奇代码在哪里第10期
  3. Zookeeper脑裂问题以及为什么推荐奇数节点讲解
上一篇:zookeeper选举机制


下一篇:java云平台开发技术,成功定级腾讯T3-2