解读Raft(三 安全性)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 前言 之前的两篇文章更多的是在描述Raft算法的正常流程,没有过多的去讨论异常场景。 而实际在分布式系统中,我们更多的都是在应对网络不可用、机器故障等异常场景,所以本篇来讨论一下Raft协议的安全性,即在异常场景下是否会导致数据丢失、数据不一致等情况。

前言

之前的两篇文章更多的是在描述Raft算法的正常流程,没有过多的去讨论异常场景。

而实际在分布式系统中,我们更多的都是在应对网络不可用、机器故障等异常场景,所以本篇来讨论一下Raft协议的安全性,即在异常场景下是否会导致数据丢失、数据不一致等情况。

选举限制

在Raft协议中,所有的日志条目都只会从Leader节点往Follower节点写入,且Leader节点上的日志只会增加,绝对不会删除或者覆盖。

这意味着Leader节点必须包含所有已经提交的日志,即能被选举为Leader的节点一定需要包含所有的已经提交的日志。因为日志只会从Leader向Follower传输,所以如果被选举出的Leader缺少已经Commit的日志,那么这些已经提交的日志就会丢失,显然这是不符合要求的。

这就是Leader选举的限制:能被选举成为Leader的节点,一定包含了所有已经提交的日志条目。

回看算法基础中的RequestVote RPC:

参数 解释
term Candidate的任期
candidateId Candidate的ID
lastLogIndex Candidate最后一条日志的索引
lastLogTerm Candidate最后一条日志的任期
参数 解释
term 当前任期,用于Candidate更新自己的任期
voteGranted true表示给Candidate投票

请求中的lastLogIndex和lastLogTerm即用于保证Follower投票选出的Leader一定包含了已经被提交的所有日志条目。

  1. Candidate需要收到超过版本的节点的选票来成为Leader
  2. 已经提交的日志条目至少存在于超过半数的节点上
  3. 那么这两个集合一定存在交集(至少一个节点),且Follower只会投票给日志条目比自己的“新”的Candidate,那么被选出的节点的日志一定包含了交集中的节点已经Commit的日志

日志比较规则(即上面“新”的含义):Raft 通过比较两份日志中最后一条日志条目的索引值和任期号定义谁的日志比较新。如果两份日志最后的条目的任期号不同,那么任期号大的日志更加新。如果两份日志最后的条目任期号相同,那么日志比较长的那个就更加新。

日志提交限制

上图按时间序列展示了Leader在提交日志时可能会遇到的问题。

  1. 在 (a) 中,S1 是领导者,部分的复制了索引位置 2 的日志条目。
  2. 在 (b) 中,S1 崩溃了,然后 S5 在任期 3 里通过 S3、S4 和自己的选票赢得选举,然后从客户端接收了一条不一样的日志条目放在了索引 2 处。
  3. 然后到 (c),S5 又崩溃了;S1 重新启动,选举成功,开始复制日志。在这时,来自任期 2 的那条日志已经被复制到了集群中的大多数机器上,但是还没有被提交。
  4. 如果 S1 在 (d) 中又崩溃了,S5 可以重新被选举成功(通过来自 S2,S3 和 S4 的选票),然后覆盖了他们在索引 2 处的日志。反之,如果在崩溃之前,S1 把自己主导的新任期里产生的日志条目复制到了大多数机器上,就如 (e) 中那样,那么在后面任期里面这些新的日志条目就会被提交(因为S5 就不可能选举成功)。 这样在同一时刻就同时保证了,之前的所有老的日志条目就会被提交。

任期2内产生的日志可能在(d)的情况下被覆盖,所以在出现(c)的状态下,Leader节点是不能commit任期2的日志条目的,即不能更新commitIndex。

在上图最终状态是(e)的情况下,commitIndex的变化应该是1->3,即在(c)的情况下,任期4在索引3的位置commit了一条消息,commitIndex直接被修改成3。

而任期2的那条日志会通过Log Matching Property最终被复制到大多数节点企且被应用。

Raft算法保证了以下特性:

  • 如果两个日志条目有相同的index和term,那么他们存储了相同的指令(即index和term相同,那么可定是同一条指令,就是同一个日志条目)
  • 如果不同的日志中有两个日志条目,他们的index和term相同,那么这个条目之前的所有日志都相同

两条规则合并起来的含义:两个日志LogA、LogB,如果LogA[i].index=Log[i]B.index且LogA[i].term=Log[i].term,那么LogA[i]=Log[i]B,且对于任何n < i的日志条目,LogA[n]=LogB[n]都成立。(这个结论显而易见的可以从日志复制规则中推导出来)

如果本文对您有帮助,点一下右下角的“推荐”
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
7月前
|
算法 索引
|
4月前
|
Kubernetes 安全 数据安全/隐私保护
在k8S中,如何保证集群的安全性?
在k8S中,如何保证集群的安全性?
|
7月前
|
存储 算法 安全
5. raft 一致性算法
5. raft 一致性算法
|
7月前
|
存储 算法 Cloud Native
分布式之raft一致性算法
分布式之raft一致性算法
125 0
|
存储 算法 安全
Raft 共识算法1-Raft基础
Raft 是一种用于管理第 2 节中描述的形式的复制日志的算法。@fig2 以压缩形式总结了该算法以供参考,@fig3 列出了该算法的关键属性; 这些图片中的元素将在本节的其余部分进行分段讨论。
124 1
|
存储 算法 关系型数据库
浅谈 Raft 分布式一致性协议|图解 Raft
本篇文章将模拟一个KV数据读写服务,从提供单一节点读写服务,到结合分布式一致性协议(Raft)后,逐步扩展为一个分布式的,满足一致性读写需求的读写服务的过程。
808 0
浅谈 Raft 分布式一致性协议|图解 Raft
|
算法 Java 开发者
Zab 协议如何保持数据的一致性 | 学习笔记
快速学习 Zab 协议如何保持数据的一致性
206 0
Zab 协议如何保持数据的一致性 | 学习笔记
|
算法 安全
分布式一致性协议
分布式一致性协议
181 1
|
存储 算法 安全
分布式系统与一致性协议
分布式系统的设计目标一般包括如下几个方面 - 可用性:可用性是分布式系统的核心需求,其用于衡量一个分布式系统持续对外提供服务的能力。 - 可扩展性:增加机器后不会改变或极少改变系统行为,并且能获得近似线性的性能提升。 - 容错性:系统发生错误时,具有对错误进行规避以及从错误中恢复的能力。 - 性能:对外服务的响应延时和吞吐率要能满足用户的需求。