Raft分区产生的脏读问题
- 前言
- 网络分区
- 情况1 4和5分到一个分区,即当前leader依然在多数分区
- 情况2 1和2分到一个分区,即当前leader在少数分区
- 脏读问题的解决
- 官方解答
- 其他论文
- 参考链接
前言
昨天面试阿里云被问到了这个问题,在此记录一下。
网络分区
有一个raft集群如下所示,然后发生网络分区:
情况1 4和5分到一个分区,即当前leader依然在多数分区
此时4 5收不到leader的心跳,成为candidate后由于得不到多数票所以选举失败,都不会成为leader
这种情况下,客户的读写请求还是会发送给leader节点1,依然能够正常读写。
情况2 1和2分到一个分区,即当前leader在少数分区
此时在另一个多数节点存在的分区一定会选举出一个新Leader,比如3当选为新leader,此时3的term会为原来的1的term+1,而1依然是leader,term不会发生变化。
这时,客户端发生读写请求会有以下几种情况:
- 对1的写请求:1接收写请求后append log entry到followers,但只能与2通信,因此得不到多数节点的成功返回,这个请求会处于uncommited状态
- 对3的写请求:3的写请求可以得到多数节点的响应,因此能够正确返回
- 对3的读请求:3的term更新,能够直接从3读取更新的数据
- 对1的读请求:有可能出现脏读
脏读问题的解决
官方解答
针对脏读问题问题,官方给的方案是需要额外2个额外的措施来保证:
1、领导人必须有关于被提交日志的最新信息
即在它的任期里必须马上提交一条空白的日志条目,即心跳;
这段话的意思是在一个节点成为Leader之前,至少向多数节点发送一次心跳来进行确认日志情况,在没收到心跳响应之前是不能响应客户端的;
2、领导人在处理只读的请求之前必须检查自己是否已经被废除了
具体实现是Leader在响应只读请求之前,先和集群中的大多数节点交换一次心跳信息来处理这个问题,即发送一次心跳的RPC,收到响应无误之后才能返回给客户端,即每次读请求要和多数成员做一次心跳以确认自己仍然是 Leader。
其他论文
除此之外,为了解决分区读产生的脏读问题,在论文 通过 raft 的 leader lease 来解决集群脑裂时的 stale read 问题中提出了region leader的概念。
对整个系统引入一个唯一的region leader,所有的读写请求都必须在region leader上进行,region leader可以和raft集群的leader不同,此时需要将读写请求重定向给raft leader
对于上述分区结果,有以下几种情况;
- region leader和1.2在同一分区,此时3 4 5的多数分区会产生一个新的region leader,而老的region leader由于联系不上多数节点,只能等到lease过期,最新的读写会通过最新的region leader来进行(这里存疑,因为不知道region leader选举的具体过程,也没找到论文的原文,感觉可能是region leader会进行某种检查来判定自己是否可用)
- regon leader和3,4,5在同一分区:此时会选举出一个新的raft leader, region leader的读写请求会发送给新的raft leader,实现最新数据的读取
参考链接
1: https://segmentfault.com/a/1190000038171007
2: https://blog.csdn.net/chdhust/article/details/77829103