1 raft算法基本原理
raft算法是一种分布式共识算法,主要用来保证不同节点日志的一致性。
特点:raft是一种强leader模型,leader有权管理所有的日志,所有的日志都是从leader流向follower的。
raft算法将共识问题拆分成三个相对独立的子问题:选举、日志复制和状态机安全性。
选举:raft算法保证集群中始终有一个leader。每个节点随机分配一个选举超时时间。系统启动时,集群没有leader,所有节点都是follower状态,直到有一个节点选举超时,变为candidate,开始选举。candidate为向每一个节点发起投票请求,获得大多数选票后,成为leader,然后定时向其它节点发起心跳,告知其它节点集群中已经有领导者,保持自己的领导者地位。当leader宕机或产生网络分区,其它节点没有收到心跳,就会选举超时,发起新一轮选举。
日志复制:raft的主要功能就是保证各个节点日志的一致性。leader收到客户端请求,生成log,然后复制到其它节点。当大多数节点成功复制后,该log提交,leader会告知follower最新提交的日志index。提交之后的log可以应用到状态机。raft可以保证各个节点日志的一致性,但想要实现状态机(kvdb)的一致性,用户可以自由实现。
状态机安全性:如果一个服务器应用了一条日志,那么其它服务器应用的相同条目的日志的内容就是一样的。想要应用某一条日志,必须保证该日志已经提交,需要leader将其成功复制到大多数节点。follower复制日志,保证其所有日志和leader都相同。leader又不会修改自身的日志。
以上,raft实现了CAP的一致性、可用性、分区容错性。
2 怎样进行选举
节点在一定时间内没有收到心跳,选举超时,发起选举:
- 变为candidate
- trem+1
- 向所有节点发起投票
- 重置选举定时器
节点收到投票请求,进行投票:
- 每个term每个节点只能投一次票,遵循先来先服务原则;
- 限制:candidate的日志不能比自己旧(根据term和index比较)
选举结果:
- 赢得大多数选票,成为leader;
- 另一个节点成为leader;
- 没有节点成为leader,term+1,进行新一轮选举(为了尽可能避免这种情况,每个节点选举超时时间随机设置)
3 什么情况下触发领导者选举?
节点在选举超时时间内,没有收到leader的心跳,有以下几种情况:
- 系统启动时,没有leader
- leader宕机
- 产生网络分区,节点和leader在不同的分区
4 定时器重置
4.1 选举定时器重置
- 节点收到leader的有效消息,心跳/AE(必须保证leader的term不小于当前节点)
- Follower收到requestvote,且本节点同意投票
- 发起选举时
- leader转变为follower时
- 节点初始化时
-
4.2 选举超时
- follower选举超时,发起选举
- candidate选举超时,说明没有获得大多数选票,term+1,重新选举
- 选举超时作用:
- 1.没有leader的情况,触发选举;
- 2.由于每个节点超时时间是随机的,避免多个节点同时超时,进行选举,导致没有一个节点可以获得大多数选票;
- 3.确保leader切换的及时性,减少服务中断的时间,提高系统可用性
- 选举超时时间设置:
- 1.随机
- 2.保证正常情况下能收到leader的心跳,因此要比rpc响应的时间大一个数量级
- 3.考虑系统负载较重的情况,需要将超时时间设置的大一些。
- 2.保证正常情况下能收到leader的心跳,因此要比rpc响应的时间大一个数量级
- 1.随机
- 2.由于每个节点超时时间是随机的,避免多个节点同时超时,进行选举,导致没有一个节点可以获得大多数选票;
- 1.没有leader的情况,触发选举;
-
4.2 心跳定时器重置
- 发起心跳时
- 初始化时
-
5 raft怎样通过日志复制保证数据一致性
- leader:
- 接收请求,生成日志条目,追加到自己的日志中;
- 针对每个follower,生成Append Entries,将日志复制到其它节点;
- follower:
- 尝试复制AE中的日志,需要保证AE之前的条目全都和leader相同
- (term和index相同,则两个日志条目的内容相同;且可以保证前面的所有日志也都相同)
- 当大多数节点已经成功复制某日志,则该日志提交,可以应用到状态该机。
-
6 raft不会提交之前任期的日志
- 只有在当前任期有日志的情况下才提交。
- 因为在某些情况下,之前任期的日志可能被覆盖。如下:
- 之前任期的leader日志没有提交(term1的日志),当前节点当选leader(term2),把之前任期的日志复制到大多数节点,提交。但当前term没有日志或当前term的日志还没有提交,然后当前leader宕机。接下来产生的leader(term3)如果没有term1的那条日志,产生日志 之后,会将其它节点term1的那条日志覆盖。那么。同一个index的日志就要被应用两次。
- 优化:
- 当选leader后,立即提交一个no-op日志。
-
7 Raft是如何确保安全性的?
- (term和index相同,则两个日志条目的内容相同;且可以保证前面的所有日志也都相同)
- 尝试复制AE中的日志,需要保证AE之前的条目全都和leader相同
- 接收请求,生成日志条目,追加到自己的日志中;
- CAP理论有三个指标,一致性、可用性、容错性。当产生分区时,一致性和可用性只能选其一。raft倾向于优先选择一致性。
- 产生分区时,leader如果处在少部分分区,那么leader收到的请求由于无法复制到大多数节点,也就无法提交,无法应用到状态机。
- 同时,raft也兼顾可用性,确保leader失效后,快速重选一位leader.
-
8 拓扑变更
9 raft的实际应用
- 分布式数据库,如TIKV
- 实现分布式事务,如分布式锁,确保多个节点之间的操作按照一定顺序和规则进行。
-
10 raft和其它分布式算法比较
raft引入leader机制,leader负责协调和领导整个一致性过程。Paxos中没有leader概念。
raft中,所有日志通过leader进行复制和提交。Paxos中的日志复制是通过多个角色相互协作完成的。
Raft可以快速选举出leader,Paxos中角色切换较为复杂,需要进行更多的投票和协调。
相对Paxos,更容易理解、实现和维护。
11 Raft算法在分布式系统中有哪些常见的问题和挑战
11.1 问题于挑战
- Leader瓶颈:Leader节点负责所有请求的处理和日志复制,这可能会成为系统的瓶颈。如果Leader节点负载过重,会导致整个系统的性能下降。
- 网络分区:Raft算法需要保证在网络分区情况下的一致性,这可能会导致在网络分区恢复后需要进行数据的合并和冲突解决,增加了一致性维护的复杂性。
- 节点故障处理:当节点发生故障时,Raft需要进行Leader的重新选举,这可能导致一段时间内系统的不可用性和性能下降,尤其是在节点频繁发生故障时。
- 日志复制延迟:Raft算法要求日志复制必须在大多数节点上完成后才能提交,影响系统的实时性能。
- 节点动态变更:Raft算法在节点动态加入或退出时需要进行配置变更,这可能会导致系统的不稳定和数据的不一致,需要谨慎处理。
- 一致性保证:虽然Raft算法保证了强一致性,但在一些特殊情况下(如网络分区、节点故障等),可能会导致一致性级别的降低或者一致性协议的不满足,需要额外的机制来解决。
- 性能调优:在实际应用中,Raft算法需要根据具体的场景进行性能调优,包括调整心跳超时时间、选举超时时间、日志复制的策略等参数,以满足系统的性能需求。
11.2 分区处理
leader没有宕机,处在多数分区,少数分区无法重新选举出leader
leader没有宕机,处在少数分区,多数分区重新选举出leader,原来的leader失效
leader宕机
12 rpc
13 测试
在集群数量变多的时候,Raft性能可能会下降,这方面有没有思考过?
回答要点: 允许从follower读;rpc合并等raft落地的框架的优化。
有没有对性能进行过测试?用的什么工具?怎么测试的?
14 c++技术
智能指针shared_ptr
std::thread创建线程
std::lock_guard<std::mutex> g(m_mtx),RAII,函数结束后,自动释放
匿名函数