分布式理论 | 青训营笔记

73 阅读11分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天


分布式理论

常见的分布式系统

分布式存储
  1. Google File System (GFS) : google 分布式文件系统
  2. Ceph : 统一的分布式存储系统
  3. Hadoop HDFS : 基于 GFS 架构的开源分布式文件系统
  4. Zookeeper : 高可用的分布式数据管理与系统协调框架
分布式数据库
  1. Google Spanner : Google 可拓展的,全球分布式的数据库
  2. TiDB : 开源的分布式关系型数据库
  3. HBase : 开源 Nosql 数据库
  4. MongoDB : 文档数据库
分布式计算
  1. Hadoop : 基于 MapReduce 分布式计算框架
  2. Spark : 在 Hadoop 基础之上,使用内存来存储数据
  3. YARN : 分布式资源调度

故障模型

  1. Byzantine failure : 节点可以任意篡改发送给其他节点的数据,又称拜占庭故障。
  2. Authentication detectable byzantine failure(ADB) : Byzantine failure 的特例,节点可以篡改数据,但不能伪造其他节点的数据
  3. Performance failure : 节点没有在特定时间段内收到数据,即时间太早或者太晚。
  4. Omission failure : 节点收到数据的时间无限晚,即收不到数据
  5. Crash failure : 在 omission failure 的基础上,增加了节点停止响应的假设,就是持续性的 Omission failure
  6. Fail-stop failure : 在 Crash failure 的基础上增加了错误可检测的假设

拜占庭将军问题

...

共识和一致性

时间和事件顺序

基础理论

CAP 理论

选项描述
C(Consistance)一致性,指数据在多个副本之间能够保持一直的状态
A(Availability)可用性,值系统提供的服务必须一直处于可用状态,每次请求都能获得非错误的相应——但是不保证获取的数据为最新数据
P(Network partitioning)分区容错性,分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络都发生了故障

CAP 理论往往运用在数据库领域,同样可以适用于分布式存储方向。值得注意的是,我们永远无法同时满足 CAP,但是可以满足 CA, CP, AP

ID: ID_0co8
Number of Columns: 2
Largest Column: left
border:off
  • CA : 放弃分区容错性,加强一致性和可用性,其实就是传统的单机数据库的选择

  • AP :放弃一致性(强一致性),追求分区容错性和可用性,例如一些注重用户的系统

  • CP:放弃可用性,追求一致性和分区容错性,例如和钱财安全相关的系统。

ACID 理论

事务: 数据库系统中非常重要的概念,它是数据库管理里系统过程中的一个逻辑单元,它能够保证一个事务中的所有操作要么全部执行,要么全部不执行。

数据库事务拥有四个特性 ACID ,分别是 原子性,一致性,隔离性和持久性

特性解释
原子性 A原子性是指事务包含的所有操作啊要么全部成功,要么全部失败回滚
一致性 C一致性指事务必须让数据库从一个一致性状态变化到另外一个一致性状态
隔离性 I隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事物,不能被其他事物的操作所干扰,多个并发事物之间要相互隔离
持久性 D持久性是指一个事务一旦被提交了,那么对数据库的数据的改变就是永久的,即使实在数据库系统遇到故障的情况下也不会丢失提交事务的操作

Base 理论

Base 理论是对 CAP 中一致性和可用性权衡的结果,他来源于对大型互联网分布式实践的总结,是基于 CAP 定理逐步演化而来的,他的核心思想是:

Basically Avaliable (基本可用):假设系统,出现了不可预知的故障,但还是能用,相较于正常的系统而言:响应时间上的损失或者功能上的损失

Soft state (软状态):允许系统中的数据存在中间状态,并认为这种专挑不影响系统的基本可用性,即允许系统在多个不同节点的数据副本存在数据延时

Eventually consistent(最终一致性):系统能保证在没有其他新的更新操作的下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值。

分布式事务

二阶段提交

二阶段提交:为了使给予分布式系统架构下的所有节点在进行实物提交时保持一致性而设计的一种演算法。

二阶段提交法基于三个假设:

  1. 引入协调者(Coordinator) 和参与者(Participants),互相进行网络通信
  2. 所有节点都采用预写式日志,且日志被写入后即被保持在可靠的存储设备上
  3. 所有节点不会永久性损坏,及时损坏后仍然可以恢复

![[Pasted image 20230227230843.png]]

可能出现的情况:

  1. Coordinator 不宕机,Participant 宕机,需要回滚(这个时候二阶段提交还在 Prepare 状态,没有 Commit,可以回滚)
  2. Coordinator 宕机,Participant 不宕机,可以起新的协调者,待查询 Participant 状态后,重复二阶段的提交
  3. Coordinator 宕机,Participant 宕机。无法确认状态。需要管理员介入, 防止数据库进入不一致的状态。

回滚:在 Prepare 阶段,如果某个事物参与者反馈失败信息,说明改节点的本地事物执行不成功,必须回滚。

二阶段提交需要注意的问题

  1. 性能问题 两阶段提价需要多次节点之间的网络通信,耗时过大,资源需要进行锁定,徒增资源等待时间。
  2. 协调者单点故障问题 如果事务协调者节点宕机,需要另起一个新的协调者,否则这参与者处于中间状态无法完成事务
  3. 网络分区带来的数据不一致 一部分参与者收到了 Commit 的消息,另一部分参与者没有收到 Commit 信息,会导致节点之间数据不一致。一般会通过锁来进行保护,防止事务未完成而查询。
  • 日志保存在 [可靠] 的存储设备上,可靠如何保证? 单机数据库时代,通过高可用的硬件来保证。分布式时代,通常建立一层分布式文件系统,分布式块存储,分布式 KB 系统。

  • 参与者 Commit 了,但 Ack 信息协调者没有收到怎么办? 对于 Coordinator 而言,他没有收到 Ack 信息,他会以为没有连接成功,于是会回滚事务,重新建立连接。这样非常浪费资源。

三阶段提交

三阶段提交 vs 两阶段提交。 将两阶段提价的 Prepare 阶段,拆分成两个部分:CanCommit 和 PreCommit

解决了两个问题:

  1. 单点故障问题
  2. 阻塞问题

另外引入超时机制,在等待超时之后,会继续进行事务的提交

MVCC

锁的普及

悲观锁:操作数据库的时候直接把数据锁住,知道操作完成后才会释放锁,上锁期间其他人不能修改数据。

乐观锁:不会上锁,只是执行更新时判断别人是否修改数据,只有冲突的时候才会放弃操作。

MVCC

MVCC 是一种并发控制的方法,维持一个数据的多个版本使读写操作没有冲突,所有既不会阻塞写,也不会阻塞读。MVCC 为每个修改保存一个版本,和事务的时间戳相关联,可以提高并发性能,解决脏读的问题。

Spanner 论文里通过 TrueTime API 提供一个屋里始终的方式,服务器始终偏差 1 到 7ms 之间。

另外一种时间戳的实现:时间戳语言及(TSO)。采用中心化的授时方式,所有协调者想中心化节点获取始终,用法简单,实现方便,但需要两个节点都与他进行交互,会产生一些网络通信的成本,TSO 的授时中就需要考虑性能以及更好的容器。

共识协议

Quorum NWR 模型

Quorum NWR 三要素 N:在分布式存储系统中,有多少份备份数据 W:在代表依次成功的更行操作要求至少有 w 份数据写入成功 R:代表依次成功的读数据操作要求至少有 R 份数据读取成功

为了保证强一致性需要保证 W+R>N

RAFT 协议

Raft 协议是一种分布式一致性算法(共识算法),及时出现部分节点故障,网络延时等情况,也不影响各节,进而提高系统的整体可用性。Raft 是使用较为广泛的分布式协议,一定意义上来讲,Raft 也使用了 Quorum 机制。

Leader - 领导者,通常一个系统中是一主(Leader)多从(Follower)。Leader 负责处理所有的客户端请求,并向 Follower 同步请求日志,当日志同步到大多数节点上后,通知 Follower 提交日志。

Follower - 跟随者,不会发送任何请求,接受并持久化 Leader 同步的日志,在 Leader 告知日志可以提交后,提交日志。当 Leader 出现故障时。主动推荐自己为 Candidate。

Candidate - 备选者,Leader 选举过程中的临时角色。向其他节点发送请求投票信息,如果获得大多数选票,则晋升为 Leader。

Log(日志):节点之间同步的信息,以之追加写的方式进行同步,解决了数据被覆盖的问题

Term(任期号):单调递增,每个 Term 内最多只有一个 Leader

Commited:日志被复制到多数派节点,即可认为已经被提交

Applied:日志被应用到本地状态机,执行了 log 中命令,修改了内存状态。

Term - 任期号

Leader 选举过程

  1. 初始化全部为 Follower
  2. Current Term + 1
  3. 选举自己
  4. 想其他参与者发起 RequestVote 请求,retry 直到:
    1. 收到多数派请求,成为 Leader,并发送心跳。
    2. 收到其他 Leader 的请求,转为 Follower 更新自己的 Term
    3. 收到部分,但未达到多数派,选举超时,随机 Timeout 开始下一轮。

两个规则

  • 在一个人气内每个参与者最多投一票(并持久化)
  • 要成为 Leader,必须得到多数投票

新的 Leader 选举出来后,会强制覆盖原来的 Follower 的数据。

Log Replication 新 Leader 产生,Leader 和 Follower 不同步,Leader 强制覆盖 Follower 的不同步日志

  1. Leader 收到写请求w
  2. 将 w 写入本地 log
  3. 想起他 Follower 发起 AppendEntries RPC
  4. 等待多数派恢复
    1. 更行本地状态机,返回给客户端
    2. 下一个心跳就通知 Follower 上一个 log 已经被 Committed 了
    3. Follower 也根据命令应用本地状态机
  5. Follower 有问题,Leader 一直 retry

如果 Leader 出现了问题,就需要进行切主 当 Leader 出现问题,就需要进行重新选举。

  1. Leader 发现失去 Follower 的响应,失去 Leader 身份
  2. 两个 Follower 之间一段时间未收到心跳,重新进行选举,选出新的 Leader,此时发生了切主
  3. Leader 自杀重启,以 Follower 身份再次加入

问题: 老 Leader 没有失去身份,新的 Leader 已经选出,产生了双主,该如何解决?

Stale 读 发生 Leader 切换,Old Leader 收到了读请求,如果直接响应,可能会有 Stale Read,如何解决? 保证读的强一致性 读操作在 lease timeout 内,默认自己是 Leader,于是在发起一次心跳,等待 commitIndex 应用到状态机

Election timeout > lease timeout:新 Leader 上任,自从上次心跳之后一定超过了 Election timeout,旧 Leader 大概率能够发现自己的 Lease 过期。

Paxos 协议

Paxos 算法与 RAFT 算法的区别

  1. Multi-Paxos 可以并发修改日志,而 Raft 写日志操作必须是连续的
  2. Multi-Paxos 可以随机选主,不必最新最全的节点当选 Leader

Paxos 优势:写入并发性能高,所有节点都能写入。比 RAFT 的读写效率高。 Paxos 劣势:没有一个节点有完整的最新的数据,恢复数据流程复杂,需要同步历史记录。