这是我参与「第五届青训营」伴学笔记创作活动的第8天。今天的内容关于分布式理论,依次介绍了分布式系统的常见问题,设计原则,执行方法,共识协议(用于保持一致性)和2个简单应用。
1 分布式概述
分布式系统是计算机程序的集合,这些程序利用跨多个独立计算节点的计算资源来实现共同的目标。可以分为分布式计算、分布式存储、分布式数据库等。
- 优点:去中心化、低成本、弹性、资源共享、可靠性高
- 困难:普通的节点故障、不可靠的网络、异构的机器与硬件环境、安全
常见分布式系统
- 分布式存储:GFS、Ceph、Hadoop HDFS、Zookeper
- 分布式数据库:Google Spanner、TiDB、HBase、MongoDB
- 分布式计算:Hadoop、Spark、YARN
2 系统模型
2.1 故障模型
常见的6种模型(按照解决方案划分):
- Byzantine failure:节点可以任意篡改发送给其他节点的数据,是最难处理的故障
- Authentication detectable byzantine failure (ADB):节点可以篡改数据,但不能伪造其他节点的数据
- Performance failure:节点未在特定时间段内收到数据,即时间太早或太晚
- Omission failure:节点收到数据的时间无限晚,即收不到数据
- Crash failure:节点停止响应,持续性的故障
- Fail-stop failure:错误可检测,是最容易处理的故障
2.2 拜占庭将军问题(难处理)
两将军问题(数据丢失)
- 定义:两支军队的将军只能派信使穿越敌方领土互相通信,以此约定进攻时间。该问题希望求解如何在两名将军派出的任何信使都可能被俘虏的情况下,就进攻时间达成共识
- 结论:两将军问题是被证实无解的电脑通信问题,两支军队理论上永远无法达成共识
- 原因:将军A发送内容被截获(都不打)或双方都成功发送(都打)时没有问题;将军A发送信息收到但将军B的回复被截获(A不打B打)则有问题
因此,TCP三次握手在2个方向确认包的序列号,增加了超时重试。(但数据传输和达成共识本质上有区别)
三将军问题(消息被篡改)
- 定义:在同一方有两个“忠将”A和B,一个“叛徒”C,互相传递消息,消息可能丢失,也可能被篡改,当有一个将军是“叛徒”(即出现拜占庭故障)时,整个系统无法达成一致。
- 结论:由于“叛徒”C的存在,将军A和将军B获得不同的信息。这样将军A获得2票进攻1票撤退的信息,将军B获得1票进攻2票撤退的信息,产生了不一致
四将军问题
- 定义:在三将军问题上增加1个消息分发中枢D,约定如果没收到消息则执行撤退
- 原理:若D为“叛徒”,ABC无论收到任何消息,总能达成一致;若D为“忠将”,则可以完成少数服从多数的决策
当有 3m+1 个将军,其中 m 个“叛徒”时,可以增加 m 轮协商,最终达成一致。
2.3 共识和一致性
最终一致性 Eventually consistent:写入过程结束后,读取者的读取内容一致。
线性一致性 Linearizability:数据更新后通过消息同步,告知其它客户端。等同于“强一致”,需要同步。
2.4 时间和事件顺序
定义关系“happened before”,记为“->”,满足3个条件:
- 若A、B是相同节点上的2个事件,A在B之前发生,则 A -> B
- 若事件A表示某个节点发送某条消息,B是另一个节点接收这个消息,则 A -> B
- 若 A -> B, B -> C,则 A -> C
当且仅当 A -> B 和 B -> A 都不成立时,称2个时间为并发(concurrent)
Lamport 逻辑时钟
一切事件都可以放在逻辑时钟上量化
3 理论基础
3.1 CAP 理论
CAP:consistence 一致性 + availability 可用性 + network partitioning 分区容错性
在一个系统中无法同时100%具备CAP。
- CA:放弃容错,传统单机数据库
- AP:放弃一致性,重视用户体验的系统
- CP:放弃可用性,如和钱财安全相关的系统
3.2 ACID 理论
ACID 即传统数据库中事务的理论。事务是数据库管理系统执行过程中的一个逻辑单元,能够保证一个事务中的所有操作要么全部执行,要么全部不执行。
ACID:atomicity 原子性 + consistency 一致性 + isolation 隔离性 + durability 持久性
数据库中 AC 必须保证。
数据库的一致性是事务的一致性,CAP的一致性是线性一致性。
3.3 BASE 理论
关于 AP 系统(3.1中提到,放弃一致性,追求可用性和分区容错性)
BASE:basically avilable 基本可用 + soft state 软状态 + eventually consistent 最终一致性
4 分布式事务 (CP 相关系统)
4.1 两阶段提交 Two-phase Commit
三个假设:
- 2种角色:协调者 coordinator 和参与者 participant,互相进行网络通信
- 所有节点采用预写式日志,且写入后就被保存在可靠的存储设备上
- 所有节点不会永久性损坏,即损坏后可以恢复
执行流程:prepare 阶段(prepare + done)和 commit 阶段(commit + ack)
异常情况:仅 participant 宕机需要进行回滚操作,仅 coordinator 宕机可以启用新的 coordinator,都宕机需要数据库管理员介入
问题:性能问题、协调者单点故障问题、网络分区带来的数据不一致
4.2 三阶段提交
将两阶段中的 prepare 阶段拆分成 CanCommit 和 PreCommit 机制。CanCommit 阶段询问是否执行,PreCommit 阶段重新确认是否可以执行。DoCommit 阶段向所有人提交事务。
解决了2个问题:单点故障问题、阻塞问题。
此外引入超时机制,等待超时后,会继续进行事务提交。
4.3 MVCC
MVCC 是一种多版本并发控制的方法,用于维持一个数据的多个版本来保证读写操作没有冲突。(不阻塞读写)
- 悲观锁:操作时锁住,直到操作完成后释放。上锁期间其他人不能修改
- 乐观锁:不上锁,只在执行更新时判断别人释放修改数据,冲突时放弃操作
版本选取:使用物理时钟或逻辑时钟
- 物理时钟:提供 TrueTime API,master 节点维持绝对时间(对应卫星),保证各服务器之间时间差控制在一个小范围内
- 逻辑时钟:中心化授时的方式 —— 时间戳预言机 TSO,无需硬件支持
5 共识协议
5.1 Quorum NWR 模型
三要素:NWR
- N:分布式存储系统中备份数据的份数
- W:一次成功的更新操作要求至少有 W 份数据写入成功
- R:一次成功的读取操作要求至少有 R 份数据读取成功
在读取时需要向多个存储版本读取,取其中最新的版本。
为了保证强一致性,需要保证 W + R > N (必要条件)
多用于 append only 的场景,避免数据覆盖导致的版本号更新不一致。
5.2 RAFT 协议
Raft协议是一种分布式一致性算法(共识算法),即使出现部分节点故障,网络延时等情况,也不影响各节点,进而提高系统的整体可用性。Raft是使用较为广泛的分布式协议。
3种角色:leader 领导者,系统主节点,负责处理所有客户端请求,向 follower同步请求日志;follower 跟随者,不发送任何请求,接收 leader 信息后提交日志,可以推荐自己成为 candidate;candidate 备选者,leader 选举过程中的临时角色,向其他节点发送请求投票信息。
- Log 日志:节点间同步的信息,只追加写的方式进行同步
- Term 任期号:单调递增
- Committed:日志被复制到多数派节点即可认为已经提交
- Applied:日志被应用到本地机状态 —— 执行力 log 中命令,修改了内存状态
Leader 选举过程
- 初始全部为 follower
- Current Term + 1
- 选举自己
- 向其它参与者发起 RequestVote 请求,retry 直到以下3种情况:收到多数派请求成为 Leader并发送心跳;收到其它 Leader 请求转为 Follower 并更新自己的 Term;收到部分,但未达到多数派,选举超时,随机 timeout 开始下一轮
Log Replication 过程
新 Leader 产生,Leader 和 Follower 不同步,Leader 强制覆盖 Follower 的不同步日志
切主:Leader 出现问题时重新选举
Stale 读:老的 Leader 失去身份后才会选出新的 Leader。
5.3 Paxos 协议
和 RAFT 的区别:Multi-Paxos 可以并发修改日志,而Raft写日志操作必须是连续的;Multi-Paxos 可以随机选主,不必最新最全的节点当选Leader。
- 优点:写入并发高,所有节点都能写入
- 缺点:没有一个节点有完整的最新数据
6 分布式实践
6.1 MapReduce
- Mapper:将输入数据分解为多个 Job 并行处理,努力达成相互间没有依赖关系
- Shuffler:将 Mapper 的结果打乱,防止数据倾斜
- Reducer:对 map 阶段的结果进行全局汇总统计
6.2 分布式 KV
架构:每个 Node 中,根据 Key 划分 Region,每个 Region 构建单机 KV 数据库,Region 间形成 RAFT Groups 做到强一致。
容错:Node 故障时,通过 RAFT Learner 模式进行数据修复。
弹性:出现局部 Key 热点或数据膨胀时,Region 可进行 Split 操作;反之进行 Merge 操作。