一、前言
本周本来要写MapReduce中的执行细节的,但是这两天看Raft资料的时候觉得Raft中的很多思想在Redis中都有对应的设计和应用,于是就先插队两篇关于Raft的文章。第一篇我们对比Raft和Redis中一致性协议的相同与不同, 第二篇我们主要看Raft在ETCD中的实现。同样,本文假定读者对Raft和Redis集群是了解的。如果不了解Redis集群的话,推荐看下我的这篇文章
大龙:Redis集群(终篇)——故障自动检测与自动恢复(附优质Redis资源汇总)zhuanlan.zhihu.com如果不了解Raft的话, 有如下资料可以去参考。同时需要事先申明的是,下文中的Redis统一指的是Redis集群。
- 首先是Raft作者的博士论文: CONSENSUS: BRIDGING THEORY AND PRACTICE
- 然后是MIT的课程视频,老师讲的很好。
- Raft Demo网站 , 做的也很清晰,但的确少了很多细节。适合初学的时候看
- 《ETCD技术内幕》这本书中的Raft介绍部分写的还比较清晰。
分布式系统的一致性和性能常常是鱼和熊掌不可兼得。追求高的一致性,必然会带来性能的损失,而想要追求高的性能,也只能妥协于一定程度的非一致性。以下图中的数据写入为例,不同的一致性级别要求写入的节点个数是不同的, 写入节点个数越多,显然客户端需要等待的时间就会越久。Raft中采用的是QUORUM, 即确保至少大部分节点都接收到写操作之后才会返回结果给Client, 而Redis默认采用的实际上是ANY/ONE, 即只要Master节点写入成功后,就立刻返回给Client,然后该写入命令被异步的发送给所有的slave节点,来尽可能地让所有地slave节点与master节点保持一致。
那么既然两者完全是不同的一致性强度要求,为什么我们还要在本篇文章中介绍Raft在Redis中地使用并进行对比呢?一方面,正因如此,我们才能通过对比二者更好的体会不同的一致性强度要求对数据同步协议以及领导节点选举的协议的设计影响。另一方面,Raft的设计目标是”在解决分布式系统一致性的前提下,尽可能地让算法易懂“,为了达到这个目的,作者论文中实际上有很多设计不是很适合在实际场景中使用,或者有一些细节没有被考虑到。我们以Redis为例,看Redis是如何设计解决这些问题的。
从作者的论文中看,Raft协议大致有四大块: Leader Election, Log Replication, Log Compaction, Membership Change。每一大点Redis都有对应的设计部分,但是我们这篇文章主要介绍对比前三点。即研究在Raft中领导节点选举、数据同步以及持久化措施与Redis中的对应措施的异同。
二、Leader Election
Redis集群和Raft协议都采用了主从节点的结构, 只有主节点才能响应客户端的请求,从节点的唯一任务就是备份主节点的数据。当我们有多个节点的时候,什么时候选择主节点,选择谁当主节点就是两个重要的问题。前者就是Fault Detection问题, 后者才是Leader Election问题。
2.1、Fault Detection
除了集群节点初次启动的场景, 发起新的领导节点选举的前提是old leader被认为故障或者下线了。所以在发起leader election之前,如何判定旧的领导节点处于fault的状态是个需要关注的问题。
2.1.1、Raft的做法
在Raft中,所有的follower节点都是passive的, 即只接收来自leader的通信,彼此之间并不相互通信。所以每个follower都是单独去判断当前的leader是否已经故障。在Raft中有两个参数比较重要,一个是HeartbeatTimeout, 一个是ElectionTimeout。leader节点至多隔HeartbeatTimeout就要给所有的follower节点发送心跳信息,来告知所有的follower节点自己还活着,那么每个follower如果发现在上次与leader节点交互过了ElectionTimeout之后还未收到来自leade