浅谈分布式一致性协议
这是我参与「第四届青训营」笔记创作活动的第十五天
1.分布式系统
分布式系统是随着计算机和网络技术的发展而发展起来的,人们希望通过多台计算机组成的网络以协作的方式共同完成单个计算机所无法完成的任务。
1.分布式系统面临的挑战
- 数据规模越来越大
- 服务的可用性要求越来越高
- 快速迭代的业务要求系统足够易用
- 各种各样的错误
- 网络
- 磁盘
- CPU
2.理想中的分布式系统
- 高性能:可拓展、低时延、高吞吐
- 正确:—致性、易于理解
- 可靠:容错、高可用
2.一致性与共识算法
1.复制操作
- 主副本把所有的操作打包成Log,所有的Log写入都是持久化的,保存在磁盘上
- 应用包装成状态机,只接收Log作为Input
- 主副本确认Log已经成功写入到副本机器上,当状态机apply后,返回客户端
2.读操作
- 方案一:直接读状态机,要求写操作进入状态机后再返回client
- 方案二:写操作复制完成后直接返回,读操作Block等待所有pending log进入状态机
3.一致性概述
- 对于我们的KV:像操作一台机器一样,要读到最近写入的值
- 一致性是一种模型(或语义):来约定一个分布式系统如何向外界(应用)提供服务 KV中常见的一致性模型:
- 最终一致性:读取可能暂时读不到但是总会读到
- 线性一致性:最严格,线性执行 一致性的分类:经常与应用本身有关
Linearizability线性一致性是最理想、自然的
4.一致性协议的限制
- 对于分布式系统
- 拓展性:写入性能不能水平拓展
- 性能:强 Leader 的一致性协议跨地域部署时带来的额外网络开销
- 对于 KV 系统,解决方案一般是通过分片的方式水平拆组
- 引入了事务的概念
- 常见二阶段提交
5.复制协议
- 当主副本失效时,为了使得算法简单
- 我们人肉切换,只要足够快,我们还是可以保证较高的可用性。
- 但是如何保证主副本是真的失效了呢?
- 在切换的过程中,主副本又开始接收client端的请求
- 两个主副本显然是不正确的,log会被覆盖写掉
- 我们希望算法能在这种场景下仍然保持正确
- 要是增加到三个节点呢?
- 每次都等其他节点操落盘性能较差
- 能不能允许少数节点挂了的情况下,仍然可以工作
- fault-tolerance
6.共识算法
简而言之一个值一旦确定,所有人都认同
- 共识协议不等于一致性
- 应用层面不同的一致性,都可以用共识协议来实现。比如可以故意返回旧的值
- 简单的复制协议也可以提供线性─致性
- 一般讨论共识协议时提到的一致性,都指线性一致性
- 因为弱一致性往往可以使用相对简单的复制算法实现
3.一致性协议案例——Raft
1.Raft概述
- 2014年发表
- 易于理解作为算法的设计目标
- 使用了RSM、Log、RPC的概念
- 直接使用RPC 对算法进行了描述
- Strong Leader-based
- 使用了随机的方法减少约束
- 正确性
- 形式化验证
- 拥有大量成熟系统
- Raft 是在 paxos 的基础上的基础上,着重于易于理解
- 协议接口直接暴露 Log 给用户
- 强 Leader 简化 Paxos 中的二阶段
- 使用随机事件简化选主逻辑
- Raft 的基本工作原理
- 各个节点的角色
- Log 同步
- 失效节点如何恢复 Log
- 如何选举新 Leader
- Term 以及安全性的保证
- Raft 在工程中的优化
- Prevote 的应用,防止离群 Leader 重加入时引发的切主
2.复制状态机(RSM)
- RSM (replicated state machine)
- Raft中所有的consensus都是直接使用Log作为载体
- Commited Index
- 一旦Raft更新Commited Index,意味着这个Index前的所有Log都可以提交给状态机了
- Commited lndex是不持久化的,状态机也是volatile的,重启后从第一条Log开始
3.Raft角色
- Leader:所有操作的发起者,把log同步给Follower,确定log已经commit
- Candidate:候选者,向其他人发起请求是否能投票给它,多数派同意则成为Leader
- Follower:发现不存在Leader,申请成为Leader,自己变成Candidate
4.Raft Term
- 每个Leader 服务于一个term
- 每个term至多只有一个leader
- 每个节点存储当前的term
- 每个节点term从一开始,只增不减
- 所有rpc的 request reponse都携带term
- 只commit本term内的log
5.Raft主节点失效
- Leader定期的发送AppendEntries RPCs 给其余所有节点
- 如果Follower有一段时间没有收到Leader的AppendEntries,则转换身份成为Candidate
- Candidate自增自己的term,同时使用RequestVote RPCs向剩余节点请求投票
- raft在检查是否可以投票时,会检查log是否outdated,至少不比本身旧才会投给对应的Candidate
- 如果多数派节点投给它,则成为该term的leader
6.Raft安全性
1.Raft安全性-同Term
- 对于Term内的安全性
- 目标:对于所有已经的commited 的<term, index>位置上至多只有一条log
- 由于Raft的多数派选举,我们可以保证在一个term中只有一个leader
- 我们可以证明一条更严格的声明:在任何<term,index>位置上,至多只有一条log
2.Raft安全性–跨Term
- 对于跨Term的安全性
- 目标: 如果一个log被标记commited,那这个log一定会在未来所有的leader中出现Leader completeness
- 可以证明这个property
- Raft选举时会检查Log 的是否outdated,只有最新的才能当选Leader
- 选举需要多数派投票,而commited log也已经在多数派中(必有overlap)
- 新Leader 一定持有commited log,如果其他人有就不同意别人当选Leader,且 Leader永远不会overwrite log,只会append不会修改之前的log
3.安全性验证
Raft使用 TLA+进行了验证
- 形式验证(Formal Method)以数学的形式对算法进行表达,由计算机程序对算法所有的状态进行遍历
4.发展方向
- 一致性协议作为系统
- 分布式日志:暴露日志的接口提供给上层应用,提供灵活高可用的一致性服务
- 高性能一致性协议
- 低延时:结合 RDMA 网络以及可编程交换机,实现 us 级别操作。
- LeaderLess:节点就地提交,降低 WAN 网络下 RTT 开销
- Paxos 与 Raft 的相互关联
- 移植 Paxos 的研究到成熟