3-1. 分布式系统(笔记)
Course:电子科技大学 - 分布式系统
Textbook:《分布式系统:概念与设计第五版》- George Coulouris
ISBN:9787111403920
第一章 分布式系统特征
1. 分布式系统构建原因
主要动力来自于对资源共享的期望,共享资源可以是硬件组件如硬盘,打印机,CPU,也可以是软件概念如文件,数据库,数据对象等。
2. 分布式系统定义和特征
分布式系统被定义为这样的一个系统:其硬件或软件分布在联网的计算机上,组件之间通过传递消息进行通信和动作的协调。通常具备如下显著特征:
- 并发:系统中的多个组件可能同时访问某一个共享资源
- 缺乏全局时钟:由于时钟的物理限制及网络的不确定性,组件无法同时获得一个正确的全局时钟
- 故障独立性:系统中有多个组件且每个组件都可能单独出现故障
3. 分布式系统举例
互联网和万维网,Web 搜索,在线游戏,电子邮件,电子商务,网络会议
4. 分布式系统面临的挑战
异构性、开放性、安全性(包括信息资源的机密性、完整性、可用性)、可伸缩性、故障处理、并发性、透明性、服务质量
第二章 系统模型
1. 分布式系统物理模型
- 基线物理模型:由一组可扩展的计算机节点组成,通过网络传递消息,是分布式系统最小物理模型。
- 早期分布式系统:扩展自基线模型,基于局域网互连的数十个节点,支持有限的连接并提供少量服务,如共享本地打印机。
- 互联网规模的分布式系统:扩展自基线模型,通过互联网连接的可扩展节点集合,为全球提供分布式服务,如Google搜索。
- 当代分布式系统:扩展自基线模型,异构性大大增加,主要有:
- 移动计算:设备的物理位置可以移动,但服务持续可用
- 无处不在计算:计算节点不再只是台式机,还增加了大量嵌入式设备
- 云计算:从“自治节点各自完成给定任务”转向“一组节点一同提供特定的服务”
2. 分布式系统体系结构模型
2.1. C/S,P2P 两种结构
C/S 即客户服务器模式,分布式系统中最常用的体系结构,在这种体系结构中,客户可以与不同的服务器进行交互,而一台服务器(的进程)既可以是真实客户的服务器,也可以扮演其它服务器的客户。
P2P 即对等体系结构,在这种体系结构中,涉及一项任务的所有进程作为对等方扮演相同的角色,实践中通常所有参与进程运行相同的程序并提供相同的接口(如应用层的多集群部署)。
2.2. 分层模型,层次化模型
分层指将复杂系统垂直分为若干层,每层利用下层服务而不关心其细节(如 OSI 七层模型),分层模型在分布式系统中就是将较大的服务垂直组织成多个服务层。
层次化模型指的是组织给定层功能的技术,可以理解为同一层服务的水平拆分(比如组织应用层时,将用户视图、应用逻辑、数据管理分离)。
3. 交互,故障,安全三种基础模型
交互模型:考虑影响交互的两个主要因素(通信性能和计算机时钟),有两种不同的设计,分别是同步分布式系统和异步分布式系统。前者规定:进程执行每一步的时间都有上限和下限,通过通信信道传递的每个消息在已知的时间范围内收到,每个进程都有本地时钟,它的时钟漂移率在一个可控范围内;后者规定:对进程的执行速度没有限制,消息传递延迟可以任意长,时钟漂移率可以是任意的(互联网的设计就是基于异步分布式系统)。
故障模型:定义了故障可能发生的方式,分为遗漏故障(进程或通信信道不能完成它应该完成的动作,如进程崩溃、消息缓冲区溢出)、随机故障或拜占庭故障(可能出现的最坏故障,如响应错误的值、消息损坏)、时序故障(只适用于同步分布式系统,如进程运行超时,消息超时或者时钟漂移率超限)。
安全模型:用于描述在开放的分布式系统中,对进程和通信信道可能的威胁及保护措施。如服务器收到假冒的客户请求,客户收到被篡改的服务器响应,分布式拒绝服务攻击,通信信道监听等。密码学、安全信道可以用于防范这些问题。
4. 同步,异步两种不同分布式系统
同步分布式系统中规定,进程执行每一步的时间都有上限和下限,通过通信信道传递的每个消息在已知的时间范围内收到,每个进程都有本地时钟,它的时钟漂移率在一个可控范围内。
异步分布式系统中规定,进程的执行速度没有限制,消息传递延迟可以任意长,时钟漂移率可以是任意的(互联网的设计就是基于异步分布式系统)。
第三章 时间和全局状态
1. 事件,进程历史概念
事件:发生了一个动作(通信或状态转换),该动作由一个进程完成。
进程历史:在该进程中发生过的一系列事件,且按照发生在先关系排序(类似时间线)。
2. 时钟漂移及产生原因
时钟漂移指两个时钟的读数间的瞬时不同(理解为每一个时钟 “1s” 都不完全一样长),因为时钟的实现基于晶体振荡频率,而两个不同振荡器的频率不可能完全一致,甚至温度变化也会引起频率变化,所以会产生时钟漂移。尽管这个差异很小,但长期累积起来仍会产生可感知的时间差异。
3. 内部、外部物理时钟同步
内部同步:指如果两个时钟同步到了已知精度,那么我们可以通过本地时间度量在不同计算机上发生的两个事件的时间间隔,即使它们没有与外部时间源同步。
外部同步:指使用权威的外部时间源对本地时钟进行同步。
4. 物理时钟正确性
通常,如果一个硬件时钟的漂移率在一个已知的范围内(该范围通常由制造商提供),那么该时钟就是正确的,这保证了时间误差是有界的。
5. 物理时钟同步的三种方法
Cristian 方法
使用一个时间服务器,它连接接收 UTC 信号的设备,用于外部同步。之后,其它主机(进程)向服务器发送“请求时间”消息并记录发送时间 \(t_{mr}\),服务器返回自己的时间 \(t\),再根据返回消息的到达时间 \(t_{mt}\) 估计往返时间 \(t_{round}\),其中 \(t_{round} = t_{mt} - t_{mr}\),即可估计自己应该设置的值 \(T \approx t + (t_{round} / 2)\)。
尽管可以通过多发送几个请求减少误差(原书:选择最小的 \(t_{round}\) 值以给出最精确的估计,因为最精确的结果源于两个消息在接近 min 的时间传输),但此方法仍然不一定足够可靠,因为这依赖于(无法保证的)往返时间误差与所要求的精确度相比足够小,或者单个时钟服务器故障导致整个系统无法进行时钟同步,因此主要用于内部网络。
Berkeley 方法
不需要外部精确时间源,仅用于内部同步。选择一台协调者计算机作为主机,主机定期轮询其它从属机,从属机将它们的时钟返回给主机,主机观察往返时间来估计从属机的本地时钟,并计算应调整值(正或负)的平均值。
此方法使用了类似 Cristian 方法估计往返时间的策略,因此也会存在一定误差。且主机故障后要选取另一台主机接管,但该方法没有保证选举在有限时间内完成。
网络时间协议(NTP)
定义了时间服务的体系结构和在互联网发布时间信息的协议,是如今互联网设备广泛使用的时钟同步协议。该协议的设计目标:
- 提供一个服务,使得跨互联网的用户可以和 UTC 进行(可接受误差范围内的)精确同步,依赖于过滤时序数据的统计技术
- 提供可靠服务,依赖于冗余服务器并在服务器之间设置冗余路径
- 可以经常进行同步,以抵消大多数设备的时钟漂移,且能扩展到处理大量客户和服务器场景
- 提供对时间服务器的保护,使用认证技术检查时序数据
下图为 NTP 服务器之间的消息交换(视 A 为客户机,B 为 NTP 服务器):
其中偏移量的估计 \(o_i\),准确度的估计 \(d_i\) 计算公式如下:
6. 逻辑时钟
Lamport 发明的一种简单机制,可以数字化发生在先排序。它规定每个进程维护自己的逻辑时钟(一个单调增长的计数器),进程 \(p_i\) 用它给事件加上 Lamport 时间戳 \(L_i\)。若进程触发了某个事件,则将该事件标注时间戳为 \((L_i + 1)\);发送消息时,在消息中附带 \(t = L_i\);接收进程接收消息事件被标注时间戳为 \(max(L_j, t)\)。
7. 发生在先关系、并发关系及分布式系统中的事件排序
发生在先关系/因果序/潜在的因果序
- 若对于进程 \(p_i\) 内的两个事件 \(e \rightarrow_i e^{'}\),则有事件顺序 \(e \rightarrow e^{'}\),表示 \(e\) 在 \(e^{'}\) 之前发生
- 对于任意消息 \(m\),均有 \(send(m) \rightarrow receive(m)\)
- 满足传递性,\(e \rightarrow e^{'}, e^{'} \rightarrow e^{''} \Rightarrow e \rightarrow e^{''}\)
基于以上规则,若对于事件 \(e, e^{'}\) 组成的偏序满足以上条件,则称它们是发生在先关系,记作 \(e \rightarrow r^{'}\)
并发关系
两个事件不能由发生在先关系进行排序,一般发生在不同进程中且没有因果关系,记作 \(a || b\)
事件排序
有因果关系的事件顺序可以由发生在先关系描述,但发生在先关系并不一定表示两个事件有先后顺序,如并发关系
8. Lamport 逻辑时钟、全序逻辑时钟及向量时钟
Lamport 时钟:Lamport 发明的一种简单机制,可以数字化发生在先排序。它规定每个进程维护自己的逻辑时钟(一个单调增长的计数器),进程 \(p_i\) 用它给事件加上 Lamport 时间戳 \(L_i\)。若进程触发了某个事件,则将该事件标注时间戳为 \((L_i + 1)\);发送消息时,在消息中附带 \(t = L_i\);接收进程接收消息事件被标注时间戳为 \(max(L_j, t)\)。
全序逻辑时钟:全局逻辑时间戳定义为 (Lamport 时间戳,进程标识符)并规定 $T_i \le T_j, i \le j \ \iff \ (T_i, i) < (T_j, j) $,尽管进程标识符的比较一般没有实际意义,但在诸如临界区排序(同时请求时按进程标识符从小到大进入)时还是可以实现相关功能的。
向量时钟:向量时钟用于克服 Lamport 时钟的缺陷(并发关系场景下,尽管 \(L_i < L_j\) 但无法推出 \(e_i \rightarrow e_j\))。假设系统中有 N 个进程,则向量时钟定义为一个 N 维整数向量,每个进程维护一个自己的向量时钟
9. 割集、割集的一致性、一致的全局状态概念
割集:分布式系统所有进程全局历史的子集,是进程历史前缀的并集
割集的一致性:割集 C 是一致的,即对于任意事件 \(e \in C, f \rightarrow e \iff f \in C\),即有果必有因
一致的全局状态:对应于一致割集(增量序列)的状态 S0 -> S1 -> S2 -> …(系统的执行可以描述成系统全局状态之间的一系列转换)
10. Chandy-Lamport 快照算法(Spark、Flink 都有类似实现)
算法目的是记录所有进程的进程状态和信道状态,所记录的进程状态组合可能不完全切合实际的时间点(可能进程 \(p_i, p_j\) 记录的最后事件分别是 \(a, b\),但实际两个事件并不是发生在同一时间),但一定是一致的(中间没有事件缺失)。算法有如下假设
- 不论是信道还是进程都不会出现故障,通信是可靠的,每个发出的消息最终会被完整接收一次
- 信道是单向的,提供 FIFO 的消息传递
- 进所有程组成的图是强连通的,即任意两个进程之间都有信道(接收信道、外发信道)
- 任一进程都可在任一时间发起全局快照
- 快照时,进程可以继续执行或者发送接收消息
算法定义了两个规则:标记发送规则和标记接收规则。前者强制记录下自己状态的进程立即发送一个标记信息,后者强制没有记录状态的进程去记录自己的状态。任何进程都可以在任何时间开始这个算法,下图是两个规则的伪代码:
第四章 协调和协定
1. 分布式互斥的含义
分布式进程常常需要协调它们的动作,如访问共享资源时需要互斥来防止干扰并保证一致性,这对应操作系统领域常见的“临界区”问题。然而分布式系统中原有互斥方法基本均失效,需要一个仅基于消息传递的分布式互斥解决方案。基本要求如下:
- ME1. 安全性(互斥):在临界区一次最多有一个进程执行
- ME2. 活性(有限等待):进入和离开临界区的请求最终将成功执行
- ME3. 发生在先顺序(happen-before):先请求进入临界区的进程先进入临界区
常用评价标准:
- 带宽:消耗的带宽,与进入和退出临界区发送消息的数量成正比
- 延迟:每次进入和退出操作导致的客户延迟
- 吞吐量:用一个进程离开临界区和下一个进程进入临界区之间的同步延迟来衡量
2. 解决分布式互斥的方法:中央服务器、令牌环、组播+逻辑时钟、Maekawa 投票算法
中央服务器:使用一个中央服务器进行临界区进入授权,要进入临界区的进程向该服务器发送消息并等待应答。满足 ME1,ME2,不满足 ME3,缺点是服务器可能会成为整个系统的性能瓶颈
令牌环:将所有进程安排在一个逻辑环上,通过获取在进程间沿着环单向传递的令牌(消息),来实现互斥。环的拓扑结构可以和计算机物理位置无关。满足 ME1,ME2,不满足 ME3,该算法可能会消耗更多的网络带宽。
组播+逻辑时钟:要进入临界区的进程组播一个消息,只有在其他进程都应答了这个消息后才能进入,如果消息接收进程没有进入临界区,或者想要进入临界区但向量时钟较大(后发生),则马上给出应答消息,否则入队该消息且暂时不给出应答消息。进程退出临界区时,对队列中未应答的消息给出应答。满足 ME1,ME2,ME3。
Maekawa 投票算法:每个进程关联一个选举集,每个选举集有相同数量进程,任意两个选举集之间有交集(同一个进程)防止同时当选,进程进入临界区需要获得足够的选票。大概过程:进程发送请求进入临界区消息给自己选举集中的所有进程,包括自己,在收到所有应答之前,不能进入临界区。选举集中的进程只要不是自己在临界区中,或者已经给别人投了票,就应该立即发送应答消息,否则入队消息暂时不给出应答。此方法满足 ME1,但是易死锁,改进版中,进程按照发生在先顺序应答队列中的请求,无死锁且满足 ME3。
3. 分布式选举含义
选择唯一的一个进程来扮演特定角色的算法称为选举算法。
4. 解决分布式选举的方法:环、霸道算法
基于环
将进程组织为逻辑环,只有相邻进程间可以单向通信(如顺时针)通信。最初每个进程都是非参与者,任何进程均可开始一次选举,将自己标记为参与者,顺时针发送选举消息给邻居。选举流程如下:
- 如果到达的标识符较小,自己又不是参与者,则将标识符替换为自己的(晋级参与者)并向后转发消息;如果已经是参与者,则不修改该消息并原样传递。
- 如果收到的选举消息中,标识符是自己的,则当选为协调者,将自己标记为非参与者并转发当选消息(选举结束)
最坏情况下,共需要 (N - 1) + N + N 个消息完成选举,即(传递选举消息到最大节点 + 包含最大节点的选举消息被沿环传递回该节点 + 沿着环传递一周的当选消息)。
霸道算法
假定每个进程都知道哪些进程有更大的标识符,且可以和所有这些进程通信。消息类型分为:Election、Answer/alive、Coordinator/victory。当进程监测到 leader 失联或者某个进程从故障中恢复时会发起选举,选举流程如下:
- 进程 \(p\) 的标识符是最大的,直接向所有进程发送 victory 消息
- 进程 \(p\) 的标识符不是最大,且 leader 失联,向所有比自己大的进程发送 election 消息。如果收到 alive 消息则停止发送 election,等待 victory 消息。一段时间等不到重新开始选举
- 进程收到了比自己小的进程发来的 election,回复一个 alive,重新开始选举流程
- 进程收到 victory 消息,则将发送者标记为 leader
5. 组通信的协调与协定
5.1 基本组播、可靠组播的区别
组播/组通信
如何将一条消息在兼顾可靠性和某种顺序策略的基础上,保证传递给组内所有成员
基本组播
- 定义基本组播原语 B-Multicast,用于应用层(组播进程)调用协议层(组播协议)实现基本组播;其简单实现方案可以让协议层向组成员发送一对一的 send 请求
- 定义基本交付原语 B-Deliver,用于协议层向应用层(组播接收进程)交付组播消息;对于网络层 receive 到组播消息的进程,通过调用该原语交付给应用层
- 一种提高发送效率的方法,使用多线程并发执行 send 操作,但这可能会带来确认爆炸,缓冲区被迅速填满并增加消息丢弃的可能性
- 最终实现目的:只要组播进程不崩溃,一个正确的接收进程终将交付该消息给应用层
可靠组播
- 完整性(integrity):一个正确(没有故障)的进程 Deliver 一个消息至多一次
- 有效性(validity):如果一个正确的进程 Multicast 了某个消息,那么它自己终将会 Deliver 该消息给自己
- 协定(agreement):如果一个正确的进程 Deliver 了某个消息,那么该组中的其它正确进程终将 Deliver 该消息
其中有效性和协定共同保证了整个系统的 liveness:如果某个正确的进程 Multicast 了某个消息,那么目标组内的所有正确进程都终将 Deliver 该消息。
5.2 实现可靠组播的方法
协定表明了 B-Multicast 不能再基于一对一的 send 来实现,因为组播进程在 send 中途出现故障时,会导致剩余进程无法 Deliver 该消息。可行方案如下:
- 基于 B-Multicast 实现可靠组播:核心思想是让所有接收进程在 Deliver 之前执行一次 Multicast,即每一个正确接收的进程都作为组播进程的中继。这样即使组播进程中途故障,也会有正确接收的进程发出 Multicast 给剩余进程。缺点是效率低下,同组内 N 个进程都要接收同一个组播消息 N 次。且系统中的所有进程都要实现对重复消息的过滤
- 基于 IP 组播实现可靠组播:将 IP组播、捎带确认法、否定确认结合起来,实现可靠的 Multicast 和 Deliver
6. 共识、交互一致性及拜占庭将军问题含义
这三类问题统称为协定,即在一个或多个进程提议了一个值应当是什么后,使系统内所有进程对这个值达成一致的意见。
7. 三个、四个拜占庭将军问题
三将军问题
假设有三个独立的拜占庭将军 A,B,C,他们之间只通过信使进行通信,现在他们需要协商一个问题:明天要进攻还是撤退。这种情况下,为达成一致只需要使用少数服从多数原则,即只要两个人意见相同即可。但不幸的是,三人当中可能会出现叛徒,考虑如下情况,A、B 做出了相反的决策,此时 C 分别向 A、B 发出不同的决策,这就会导致 A、B 采取不一致行动,从而导致失败。可以证明三将军问题是无解的,即无法找出三人之中的叛徒。
四将军问题
四将军问题与三将军问题类似,但不同之处在于,四将军问题存在可行的解决算法。
拜占庭将军问题,本质上是在描述分布式系统中可能出现最坏情况的一个故障模型:由于系统中存在拜占庭故障(不响应、回复错误消息、回复不一致消息等)的节点,导致系统出现了不一致状态或行为,而且这个不一致无法感知到。如果存在一个算法能够使得系统在出现拜占庭故障时仍能保持一致性,那么这个算法基本上可以应用在各种场景下系统一致性的保证。因为没有比拜占庭故障更离谱的故障了。
但在实际应用中,并不一定需要如此苛刻的模型,因为系统中大多数的节点不太可能像拜占庭将军一样有主观恶意,除非节点已经感染了病毒,一般情况下能避免服务器宕机这类错误导致的不一致就可以了。
8. Paxos 算法
Paxos 算法将系统中的节点分为三种不同的角色(类比场景为国会议案投票):
- Proposer:提议者,向集群提出某个提议
- Acceptor/Voter:投票者,对提议者的提议进行投票,只有形成法定人数(一般是多数派)时提议才会被接受
- Learner:接受者,对任意被接受的提案都同意(混子)
算法分为两大四小阶段:
- 提案和投票
- Prepare:Proposer 提出一个 N 号提案,并请求 Acceptors 接受此提案
- Promise:Acceptor 回应 Proposer 的提案,只要 Acceptor 之前收到的提案号都比 N 小,则返回接受;否则拒绝该提案
- 确认和通过
- Accept:Proposer 收到了足够多的 Acceptor 的接受回应,则向 Acceptor 发起 Accept 请求,包含提案号和内容
- Accepted:Acceptor 在此期间没有收到更大的提案,则返回 Accepted 表示该提案通过,否则忽略。若通过则把通过的提案发给 Learner
Basic Paxos 存在活锁问题(尽管系统没有被真正阻塞,但因为某些条件不满足使得进程一直在重复执行“尝试-失败”,而无法继续向下执行任何有实际业务意义的代码),比如两个或多个 Proposer 在提案和投票阶段相互竞争,导致长期都不能通过任何提案。解决方法是使用 Random Timeout 策略,让冲突的 Proposer 等待一段随机时间,减少冲突的可能。
9. Raft 算法(动画演示)
Raft 算法将系统中的节点分为三种不同的角色:
- Follower:默认节点状态
- Candidate:参选者,即参与竞选 Leader 的节点,会从 Follower 切换为 Candidate
- Leader:竞选成功的节点,会从 Candidate 切换为 Leader
系统中的主要流程如下:
- Leader 会定时(Heartbeat Timeout)向 Follower 发送心跳(Heartbeat),每个 Follower 都维护一个 Random Timeout,每收到一次心跳则重置超时倒计时(Election Timeout)
- Leader Election:任一 Follower 随机一段时间后(Election Timeout,150ms ~ 300ms)没收到心跳则可晋级 Candidate 并启动新的选举,得到多数 Follower 同意的 Candidate 即可当选 Leader,此时任期递增(Term+1)。如果多个 Candidate 同时启动选举,则会等待随机时间重新开始。
- Log Replication:客户端发起的变更操作均请求到 Leader,生成一个 Log Entry 并复制到所有 Follower,完成后 Leader 响应客户端。这样系统状态是一致的
- 网络分区时,系统会出现多个 Leader,当网络分区修复后,任期小的 Leader 会自动下台,小任期下的 Follower 均会回滚自己的 Log Entry 并和有效 Leader 保持一致
第五章 事务和并发控制 & 分布式事务
1. 串行等价性的概念、充要条件及应用
串行等价性:如果并发事务交错执行的结果,一定和某种依次串行执行每个事务的结果相同,就称这是一种串行等价的交错执行
串行等价性充要条件:两个事务中所有的冲突操作,都按照相同的次序在它们访问的对象上执行
串行等价性应用:可作为一个标准用于生成并发控制协议
2. 事务的三种基本控制方法:锁、乐观方法、时间戳,它们的原理、实现、比较
2PL
两阶段加锁,最简单的并发控制。考虑的问题是如果并发控制不事先将所有需要的锁申请好,而是释放锁后还允许再次申请,很有可能导致事务之间出现死锁(2PL 类似死锁预防中的破坏请求并保持条件)。而且如果同一事务内两次操作同一对象之间,其它事务修改了这个数据对象,进而导致不可重复读(同一事务内两次读取到不一致的数据)或丢失更新问题。
S2PL
严格的两阶段加锁。其规定写锁要在事务提交或放弃时才可以释放。因为 2PL 下可能出现脏读或级联放弃问题,S2PL 作了更严格的限制,避免了这些问题。
OCC
乐观并发控制。其假设大多数事务可以在互不干扰的情况下完成。当事务运行时,事务不需要申请资源的锁,便可以使用这些资源。OCC 通过维护本地数据集,并在验证阶段检查是否存在冲突,若存在冲突则回滚。所以通常用于低数据争夺的场景。
当冲突较少时事务的完成将会没有管理锁的消耗,并且不需要令事务等待其他的事务锁释放,相比基于悲观锁的并发控制,具有更好的并发效率。然而,如果数据资源争夺较为频繁,反复回滚和重启事务的花费将会极大地降低性能,通常认为在这种情况下,其他并发控制方法拥有更好的性能。
OCC 事务验证,每个事务在进入验证阶段前(执行 closeTransaction 时)被赋予一个事务号,有如下两种验证方式
- 向后验证:检查当前事务和其它较早的重叠事务之间的冲突,即当前事务的读集和其它事务的写集是否冲突
- 向前验证:检查当前事务和其它较晚的重叠事务之间的冲突,即当前事务的写集和其它事务的读集是否冲突
其中向前验证处理冲突的方式更加灵活。向后验证因为对比的事务都已经提交,只能放弃当前事务。通常事务的读集和要远大于写集和,向前验证用小集合和大集合比较而向后验证相反;向后验证要保存其早期事务的写集和,需要额外开销;向前验证必定允许事务并发。
MVCC
多版本并发控制。这种策略下,数据库系统为每条数据维护多个快照/版本(Snapshot),通过起止两个时间戳(Begin Timestamp / End Timestamp)维护副本的可见性,也可称作版本号。读写进行的不同操作如下:
- Update:创建一条新版本的数据
- Delete:更新End Timestamp
- Read:通过起止时间戳判定记录是否对当前事务可见
CMU 将并发控制方式分为两种,一种是基于 2PL 的,悲观锁相关的都可规纳入此类;一种是时间戳方法,OCC 和 MVCC 都属于这种。
并发控制方法 | 原理 | 优点 | 缺点 |
---|---|---|---|
锁(严格两阶段加锁) | 1. 基于最简单的互斥锁:对事务所访问的对象加锁,若已被锁则挂起 2. 2PL 规定事务的执行分为两个阶段,第一阶段是扩展阶段,在这个阶段获取所有需要的锁;第二个阶段是收缩阶段,这个阶段释放锁; 3. S2PL 规定所有执行过程中获取的锁,必须在事务提交或放弃后才能释放 4. 在 S2PL 的基础上,扩展锁的类型为共享锁/排他锁(读锁/写锁),提高并发度(混合粒度加锁) |
1. 实现简单 2. S2PL 解决了脏读和更新丢失问题,避免了连锁放弃 3. 对更新操作为主的事务有更好的性能 |
1. 存在死锁问题,而死锁的解除方法并不理想 2. 锁增加了额外开销 3. S2PL 为了避免连锁放弃需要延长锁的持有时间到事务结束,潜在降低了并发度 |
乐观并发控制 | 1. 工作阶段:事务拥有访问对象的临时版本,读和写都在临时版本上进行 2. 验证阶段:事务结束前验证事务(向前验证和向后验证),验证失败后采取冲突解除机制(放弃当前事务或其它冲突事务) 3. 更新阶段:验证通过后,持久化临时版本后即可提交 |
1. 对于冲突较少的并发事务乐观策略效率要优于悲观策略(两阶段加锁,时间戳排序) | 1. 对于写操作更多的有冲突事务,效率低于悲观策略,很有可能导致事务放弃 2. 事务放弃时需要做更多的工作 |
时间戳排序 | 1. 事务中每个操作在执行前都要先进行验证,如果验证不通过则事务被立即废弃 2. 每个事务在启动式被赋予一个唯一的时间戳,不同事务的操作可以根据它们的时间戳进行全排序 3. 只有在对象上的最后一次读/写操作是由一个较早的事务执行的,当前事务对该对象的写操作才是有效的;只有在对象上的最后一次写操作是由一个较早的事务执行的,当前事务对该对象的读操作才是有效的 |
1. 对于只读事务优于严格两阶段加锁 | 1. 对于写操作更多的事务,效率低于两阶段加锁 |
第六章 复制
1. 复制的概念、动机、基本要求
复制的概念:在多个计算机中进行数据副本的维护
复制的动机:是保证分布式系统有效性的关键技术之一,可用于增强性能,提供高可用性和容错能力
复制的基本要求:
- 透明性:客户不知道也不需要知道多个物理副本的存在,以及它们之间的组织方式,客户只需要知道有一个完整的逻辑数据对象即可。
- 一致性:针对一个 “复制的数据对象” 的操作,是否能得到满足这个对象正确性要求的结果。比如多人编辑的协作文档,不同用户应当看到同样的内容,如果看到不一致的内容通常是不可接受的。
2. 复制的系统模型: 主动复制、被动复制
主动复制
每个副本管理器都被设计为一个状态机,充当同等角色并组织为一组。前端将消息组播到副本管理器组,所有副本管理器按照独立但相同的方式给出应答。任何一个副本管理器崩溃都不会影响整体系统的性能和可用性。一般还可以应对拜占庭故障,因为前端可以比较多个副本管理器的应答。
被动复制
任何时候都有一个主副本管理器和多个次备份副本管理器。前端只和主副本管理器通信并获取服务,主副本管理器执行操作并将更新发送给副本。如果主副本管理器出现故障,那么某个备份可升级为主副本管理器。
3. 单拷贝串行化的概念、“读一个/写所有”方案原理、适用条件及本地验证方法
4. Gossip 系统的两个保证、体系结构(含关键数据结构)及基本操作
两个保证
- 服务一致性保证:不管时间如何推移,保证每个用户获得的服务是一致的。比如客户写入了一个值,只要后续没有更新操作,客户不论何时通过哪个副本管理器去访问,都应该是该值
- 松弛一致性保证:所有副本管理器终将收到所有的更新,这其实是降低了一致性来保证高可用性。因此 Gossip 不适合于接近实时的更新复制系统如共享文档
体系结构
- 前端可以选择任意副本管理器
- 副本管理器定期通过 Gossip 消息来传递客户的更新
基本操作
- 查询操作
- 更新操作
5. Coda 体系结构及复制策略
...
第七章 分布式文件系统
1. 分布式文件系统的需求
- 透明性:访问透明性、位置透明性、移动透明性、性能透明性、伸缩透明性
- 并发更新:支持对共享资源的并发控制
- 文件复制:一个文件可以组织为分布在不同位置的多个拷贝
- 硬件和操作系统的异构型
- 容错:故障可继续服务、幂等操作、无状态服务器
- 一致性:单拷贝更新,并发访问时只能看到一个一致的文件存在,即使访问了不同的拷贝
- 安全性:请求认证机制
- 效率:要达到传统文件系统的效率
2. 文件服务体系结构,即三个组件、作用、接口,设计理念
三个组件及作用
- 平面文件服务:对文件内容进行操作,提供唯一的文件标识(UFID)
- 目录服务:提供文件名到 UFID 的映射
- 客户端模块:提供应用程序对远程文件服务透明存取的支持,如对目录的迭代请求,缓存文件
接口
- Read(FieId, StartIndex, Length)
- Write(FieId, StartIndex, Data)
- Create():生成长度为 0 的新文件,并为其指定 UFID
- Delete(FieId)
- GetAttributes(FieId)
- SetAttributes(FieId, Attr)
设计理念
- 除了 Create,其它所有的操作都是幂等的
- 无状态服务器设计
- 通过指定下标,设计更加通用的接口
- 不提供打开关闭文件接口,简化设计
3. NFS(Sun 网络文件系统)体系结构、NFS服务器操作、路径解析、缓存机制
为运行在 Unix 和其它系统上的客户程序,提供对远程文件的透明访问。采用对等的客户-服务器体系,即一台机器既可以作为服务器输出自己的文件,也可以作为客户端访问其它机器的文件。但在实际应用中,通常会将某些配置较高的机器作为专用服务器,其它机器作为工作站(客户端)。
4. AFS(Andrew File System)应用场景、设计理念、缓存机制、一致性
CMU 开发的为运行在工作站上的 Unix 程序提供对远程共享文件的透明访问。
设计理念
-
可以使用正常的 Unix 文件原语来访问 AFS 文件,即不需要修改原有 Unix 程序
-
可伸缩性,用以满足更多活动用户的使用需求,其关键是在客户机上缓存整个文件
- 整体文件服务:将整个文件和目录的内容都传输到客户机上
- 整体文件缓存:当一个文件或文件块拷贝到被传输的客户机上时,它会存储到本地磁盘缓存中
应用场景(一个简单的处理过程)
- 客户机请求打开一个本地缓存不存在的文件,AFS 查找后向客户机传输此文件副本
- 传输后的文件在本地 Unix 文件系统中被打开,文件描述符返回给客户程序
- 客户机进程在本地文件上执行一系列修改操作,在本地文件关闭时,会自动将该修改后的文件传回服务器,服务器更新文件内容和时间戳
- 本地文件则一直被保留,供同一个机器上的其他用户进程使用
缓存一致性
...
第八章 GFS(Google File System)
1. GFS 设计动机、设计思想、体系结构
设计动机及思想:为了满足 Google 迅速增长的数据处理需求,设计并实现了 GFS。GFS 与传统的分布式文件系统有着很多相同的设计目标,比如,性能、可伸缩性、可靠性以及高可用性。但是,其设计还受到 Google 应用的负载情况和技术环境的影响,与早期文件系统的假设都有明显的不同:
- 组件失效(系统故障)是常态而非意外事件
- 通常情况下,系统所需处理的文件都是大文件而非类似安卓文件系统那样的小文件
- 绝大部分对文件的修改操作,都是追加写,很少有随机写
- 文件系统 API 和应用程序协同设计,使得整个系统更灵活(GFS 有一些 “专用性”)
系统角色:
- Master:单节点,管理文件系统元数据以及变更日志,不存储原始文件,而元数据通常并不大
- Chunk Server:多节点,对 Chunk(文件块)进行物理存储,响应 Client 的操作(读取、写入、删除等)
- Client:GFS 的使用者,通常多节点,会向 Master 和 Chunk Server 发出文件操作请求
2. Master 不存在性能瓶颈原因
尽管为了简化系统设计选择了单 Master 节点,但采取了一系列措施减少 Master 的压力,避免成为瓶颈:
- 客户端不通过 Master 读写文件数据,即只有控制流经过 Master,数据流不经过 Master
- GFS Client 可以本地缓存部分元数据而无需与 Master 交互
- 通过使用大尺寸 Chunk,压缩元数据等,提高了 Master 内存利用率
3. 读、写、追加操作流程
读操作流程:
- 应用程序发出读请求给 Client 程序
- Client 将请求转换为(文件名、块索引)发给主服务器
- Master 返回数据块的句柄和 Chunk Server 的位置
- Client 选择其中一个 Chunk Server,向其发送请求
- Chunk Server 返回请求的数据给 Client
- Client 将数据交付给应用程序
写操作流程:
- Client 发送请求到 Master
- Master 返回块的句柄和 Chunk Server 的位置信息
- Client 将写数据发送给所有 Chunk Server,数据存储在 Chunk Server 的缓存中,稍后会持久化
- Client 发送写命令到主 Chunk Server
- 主 Chunk Server 给出写的次序,并将该次序发送给从 Chunk Server
- 从 Chunk Server 响应主 Chunk Server
- 主 Chunk Server 响应客户端写操作完成
追加写操作流程:
-
应用程序提出添加操作的请求给 Client,其将请求发给 Master
-
Master返回块句柄和 Chunk Server 的位置信息
-
Client 将要写入的数据推给各个 Chunk Server
-
主 Chunk Server 检查添加操作是否会导致该块超过最大的规模
- 如果超过,将该块扩充到最大规模,其它 Chunk Server 做同样的操作,同时通知 Client 该操作需要在下一个块上重新尝试
- 如果不超过,主 Chunk Server 将数据写入后,告诉其它的 Chunk Server 在同样的 offset 处追加写数据
-
主 Chunk Server 向 Client 报告追加写成功
4. 写操作一致、确定含义及分析
...
第九章 P2P(对等系统)
1. P2P基本结构类型:中心化网络、分布式(结构化、非结构化)、混合式
2. 一致性哈希算法
是一种特殊的哈希算法,目的是解决分布式缓存的问题。在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希算法解决了简单哈希算法在分布式哈希表(Distributed Hash Table,DHT)中存在的动态伸缩等问题。
特点
- 平衡性:Hash 的结果平均分配到各个节点,从算法上解决了负载均衡问题
- 单调性:新增或者删减节点时,不影响系统正常运行
- 分散性:数据分散地存放在分布式集群中的各个节点,不必每个节点都存储所有的数据
3. 分布式哈希表主要思想
分布式哈希表技术(Distributed Hash Table,DHT)是一种分布式存储方法。在不需要服务器的情况下,每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整个 DHT 网络的寻址和存储。DHT 是实现分布式存储和下载的关键技术,现已广泛应用在P2P网络中。
4. Chord原理、Hash表分布规则、基于Finger Table的路由技术
P2P 应用中一个经典问题就是如何高效地找到存储了某个数据条目的节点。Chord 协议被设计为用于通过一个给定的 key 映射到一个服务器节点。具体到应用来说,Chord 服务器节点可能还需要存储key 对应的 value(一般是文件或数据)。
Chord 通过某个哈希算法(如 SHA-1)为每个服务器节点或所存储的 key 计算出一个 m bit 的哈希值,统称为 ID。对于服务器节点,其 ID 通过 Hashing IP 得到。所有 ID(不论是节点还是 key)都在模 2 后按顺序排列在一个环上。对于一个 ID 为 k 的 key(即 hash(key) = k),它由环上第一个 ID 不小于 k 的节点负责维护。该节点叫 ID k 的继任节点,记作 successor(k)。再直观一点的讲,successor(k) 是环上从 k 顺时针起(包括 k 本身)遇到的第一个节点。
Finger Table 路由
Finger Table 是一个列表,最多包含 m 项(m 就是哈希值的比特数),每一项都是节点 ID。假设当前节点的 ID 是 n,那么表中第 i 项的值是 \((n + 2^i) % 2^m\) 的继任者。当收到请求(key),就到 Finger Table 中找到最大的且不超过 key 的那一项,然后把 key 转发给这一项对应的节点。有了 Finger Table 之后,时间复杂度可以优化为:O(log N)。