1,Raft 协议什么作用
2,详细介绍 Raft 流程
我觉得以下这个流程是比较详细的了,
以下是带上了持久化和日志压缩的细节:
持久化:节点会定期将自己的信息,比如当前任期号、投票信息、日志条目和快照,持久化到硬盘。这是为了确保即使节点崩溃或者重启,也能从硬盘恢复到最新的状态。
恢复:当节点重启时,它首先从硬盘中读取持久化的信息,恢复其任期号、投票信息、日志条目和快照。然后,它会以跟随者的身份开始运行,等待领导者的心跳消息。
日志压缩:随着时间的推移,每个节点的日志可能会变得非常大,因此需要进行压缩。这个过程被称为快照(snapshotting)。在快照过程中,节点将当前的系统状态(状态机的状态)保存下来,并清除所有已被应用且索引值小于这个状态的日志条目。快照也需要持久化存储,以防节点重启时丢失状态。
3,follower 会响应 client 的读写操作吗
4,超过半数的决策机制如何保证 leader 日志的完整性
5,为什么使用 log,不直接写入状态机?
以下内容来自一篇知乎文章《6.5 日志(Raft Log)》,我觉得讲解比gpt4好得多:
1 Raft系统之所以对Log关注这么多的一个原因是,Log是Leader用来对操作排序的一种手段。这对于复制状态机(详见4.2)而言至关重要,对于这些复制状态机来说,所有副本不仅要执行相同的操作,还需要用相同的顺序执行这些操作。而Log与其他很多事物,共同构成了Leader对接收到的客户端操作分配顺序的机制。比如说,我有10个客户端同时向Leader发出请求,Leader必须对这些请求确定一个顺序,并确保所有其他的副本都遵从这个顺序。实际上,Log是一些按照数字编号的槽位(类似一个数组),槽位的数字表示了Leader选择的顺序。
2 Log的另一个用途是,在一个(非Leader,也就是Follower)副本收到了操作,但是还没有执行操作时。该副本需要将这个操作存放在某处,直到收到了Leader发送的新的commit号才执行。所以,对于Raft的Follower来说,Log是用来存放临时操作的地方。Follower收到了这些临时的操作,但是还不确定这些操作是否被commit了。我们将会看到,这些操作可能会被丢弃。
3 Log的另一个用途是用在Leader节点,我(Robert教授)很喜欢这个特性。Leader需要在它的Log中记录操作,因为这些操作可能需要重传给Follower。如果一些Follower由于网络原因或者其他原因短时间离线了或者丢了一些消息,Leader需要能够向Follower重传丢失的Log消息。所以,Leader也需要一个地方来存放客户端请求的拷贝。即使对那些已经commit的请求,为了能够向丢失了相应操作的副本重传,也需要存储在Leader的Log中。
4 所有节点都需要保存Log还有一个原因,就是它可以帮助重启的服务器恢复状态。你可能的确需要一个故障了的服务器在修复后,能重新加入到Raft集群,要不然你就永远少了一个服务器。比如对于一个3节点的集群来说,如果一个节点故障重启之后不能自动加入,那么当前系统只剩2个节点,那将不能再承受任何故障,所以我们需要能够重新并入故障重启了的服务器。对于一个重启的服务器来说,会使用存储在磁盘中的Log。每个Raft节点都需要将Log写入到它的磁盘中,这样它故障重启之后,Log还能保留。而这个Log会被Raft节点用来从头执行其中的操作进而重建故障前的状态,并继续以这个状态运行。所以,Log也会被用来持久化存储操作,服务器可以依赖这些操作来恢复状态。
为什么不直接写呢?
6,如何解决 split vote 的问题
分票(split vote): 这是一个选举问题,在Raft等一致性协议中可能会遇到。当一个集群中没有一个节点能够得到大多数节点的选票,从而无法选举出新的领导者时,我们就称之为发生了分票。这通常是由于网络延迟,节点启动时间不一致或者其他原因导致的。
解决方法通常是:
7,了解 paxos 吗
8,分布式锁和raft的关系
8.1 分布式锁和利用raft机制设置的锁的关系
8.2 raft的leader选举机制来实现分布式锁的一种流程
8.3 raft分布式锁和redlock分布式锁的差异
8.4 为什么raft分布式锁是强一致性的?
8.5 为什么Redlock只能提供最终一致性
8.6 redlock如何导致数据不一致
8.7 为什么节点之间的通信恢复,会发现这种冲突并解决
8.8 那先前两个客户端都持有多数锁而导致已经产生不一致的数据会被修复吗
8.9 为什么票务系统的缓存数据也要保证一致性,最终的一致性由数据库来保证不就好了吗
8.10 redlock有哪些应用场景
8.10 redlock与分布式锁的一些思考
8.11 Raft的leader 选举机制实现分布式锁时如果客户端宕机了,怎么释放锁
8.12 Raft的leader 选举机制实现分布式锁这种机制平常用的多吗
9,怎么使用分布式锁设计一个API(问的应该是怎么针对某一种业务设计一个分布式锁的API)
可以把raft实现分布式锁或者redlock分布式锁的那一套拿出来讲,大概就能让面试官满意。
10,多个请求者,加锁怎么维护状态
11,一致性
11.1 什么是线性一致性和顺序一致性
11.2 可以理解为线性一致性是支持强一致性的,但是顺序一致性是弱一致性吗
11.3 线性一致性可以理解为"所有节点上的这个操作都是要么全部执行成功,要么全部执行失败"吗
11.4 raft怎么实现线性一致性
11.5 因为raft还需要让主结点同步日志给从节点,同步的时候所有节点看到的不一定是同一份最新完整的数据吧
12,如果用同步复制呢,raft有什么问题
13,Quorum 读写这种方法相比 raft 的问题?
14,如果 Quorum 读写也去设置一个 leader ,然后先写 leader,这种情况会有什么问题
15,Etcd用过吗
16,为什么要写消息队列
17,Raft和消息队列是怎么结合起来的
18,哪些中间件用了raft?
19,cap是什么
20,zab算法
21,实现paxos算法的工程还有哪个?raft…
22,
23,为什么zk不用raft?
24,paxos的有哪些缺点
25,ZooKeeper 的ZAB协议介绍一下?
26,如果ZooKeeper中有超过半数的follower已经commit成功,但是有一个follower还没收到commit就挂掉了,重连后数据会不一致吗?
27,如果ZooKeeper中有超过半数的follower已经commit成功,但是这时leader挂掉了,重新选举时会选择之前没有成功commit的follower作为leader吗?
28,分布式系统什么情况下会出现脑裂?
29,对于一个6个节点的ZooKeeper集群,如果因为网络分区变成了两个小集群,各三个节点,请问服务还可用吗(还能进行写操作吗)?
30,raft leader与客户端交互
30.1 处理客户端的读操作时有哪些问题,如何保证读操作的安全性?
其实论文中有提到
Read-only operations can be handled without writing anything into the log. However, with no additional measures, this would run the risk of returning stale data, since the leader responding to the request might have been superseded by a newer leader of which it is unaware. Linearizable reads must not return stale data, and Raft needs two extra precautions to guarantee this without using the log.
First, a leader must have the latest information on which entries are committed. The Leader Completeness Property guarantees that a leader has all committed entries, but at the start of its term, it may not know which those are. To find out, it needs to commit an entry from its term. Raft handles this by having each leader commit a blank no-op entry into the log at the start of its term. Second, a leader must check whether it has been deposed before processing a read-only request (its information may be stale if a more recent leader has been elected). Raft handles this by having the leader exchange heartbeat messages with a majority of the cluster before responding to read-only requests. Alternatively, the leader could rely on the heartbeat mechanism to provide a form of lease [9], but this would rely on timing for safety (it assumes bounded clock skew)
翻译:可以在不向日志中写入任何内容的情况下处理只读操作。然而,如果没有额外的措施,这将有返回陈旧数据的风险,因为响应请求的leader可能已经被它不知道的新leader所取代。线性化读取必须不返回陈旧的数据,Raft需要两个额外的预防措施来保证这一点,而不使用日志。
首先,leader必须拥有提交条目的最新信息。Leader完整性属性保证Leader拥有所有已提交的条目,但在其任期开始时,Leader可能不知道哪些是已提交的条目。为了找出答案,它需要提交其任期中的一个条目。Raft通过让每个leader com在其任期开始时在日志中添加一个空白的无操作条目来处理这个问题。其次,leader必须在处理一个只读请求之前检查它是否已经被删除(如果一个最近的leader被选举出来,它的信息可能是陈旧的)。Raft通过让leader在响应只读请求之前与大多数集群交换心跳消息来处理这个问题。或者,leader可以依赖心跳机制来提供一种形式的租赁,但这将依赖于安全的定时(它假设有界时钟倾斜)。
30.2 你能举一个 因为没有采取措施导致读取到旧数据的例子嘛?
答:其实就是30.3的例子
30.3 一个节点可能在什么时候不知道自己已经被新leader取代呢?
30.4 一般什么时候会网络分区
30.5 发生网络分区时,为什么流量还会被打给旧leader
30.6 应对流量打给旧leader的情况,raft会采取什么措施嘛
下面这种其实是应对写请求的流量打给旧leader导致提交错误写请求的方法,处理类似的读请求也是采用这种写的方法,就是前面论文中提到的“写no-op entry”:
30.7 当流量打给旧leader或者follower后,还会重定向到leader嘛
30.8 不能follower或者旧leader直接将请求交给leader节点处理,然后leader直接返回给客户端吗
30.9 为什么在一个新任期的开始,leader处理读操作前需要向从节点同步一个"no-op"条目呢?
因为leader选举的一个依据是日志的新旧程度(涉及到lastLogIndex即日志的最后一项索引值),但是我们一个节点的commitIndex并不是等于最后一项日志的索引值(lastLogIndex),它是依赖于各个从节点的日志复制进度的,而且commitIndex<=lastLogIndex, 所以如果在一个新任期的开始,客户端的读请求想要获取位于(commitIndex, lastLogIndex]之间的日志,那么这个时候可能读取的就是raft系统未提交的数据,这是不合法的,所以这个时候如果我规定在任期开始时,leader会在处理所有读请求之前优先写入一个"no-op"日志条目,主节点的lastLogIndex自增,然后将(nextIndex[i], lastLogIndex] 区间的日志发送给响应的从节点,这样当多数从节点的日志都接收了这个"no-op"日志项时,则leader节点也可以提交这个日志项,commitIndex更新为lastLogIndex,所以当接收到读取(commitIndex, lastLogIndex]日志的时候,获取的也是最新的数据。 相反如果主节点是旧leader,则各个从节点会拒绝接收日志并且将自己的任期号和日志相关的信息告诉这个旧leader,旧leader收到响应后更新任期号转变角色,提交"no-op"失败,可能是因为它已经不再是leader, 这个时候会拒绝客户端的读请求并且将自己获取到的leader信息返回给客户端,客户端刷新本地缓存后再将读请求发送给新leader