分布式理论课程记录 | 青训营笔记

147 阅读17分钟

这是我参与「第五届青训营」伴学笔记创作活动的第9天。 本文记录「第五届青训营」分布式理论-现代架构基石课程。本课程内容几乎都是理论,故本文也几乎全篇都是理论内容。文章内容来源于课程内容、网络资料、书籍论文,理论上不同的参考资料和书籍论文的表述可能不同,请以权威书籍论文为准。另外本文也结合一些自身理解来扩充文章的内容,以加强我们对分布式理论的理解和记忆。

一 分布式的相关概念

(一) 分布式的概念

这是一个数据爆炸的时代,大量的数据使得对计算机的储存和计算需求越来越大,而分布式正是一种低成本,可构建在多台廉价服务器之上的一种技术。

(二) 分布式的优缺点

优势:

  1. 支持大量并发用户:最核心的优势,增大系统容量,是采用分布式架构的主要原因
  2. 加快计算速度:如果一个特定的计算任务可以划分成若干并行运行的子任务,那么可把这些子任务分散到不同的节点上,它们同时在这些节点上运行,从而加快计算速度。
  3. 容错和灾备能力:分布式架构有多个节点,在某些节点出现故障时候能使用备用节点服务,冗余系统以消除单点故障,从而提高系统的可用性。
  4. 可灵活扩展:遵循正确的设计原则,能灵活拓展微服务和节点数量。

劣势和挑战:

  • 1.每个节点发生故障是一个小概率事件,但是成千上万个节点一起运行,那发生故障就是必接电故障。服务器多了则几乎每天都会发生节点故障。
  • 2.大型网络中的网络稳定性一般来说比较低,是不可靠的。。容易发生故障。而且也比较难以解决
  • 3.有时候一些程序在一些特定的环境或系统运行的很好,但是在分布式环境的情况下,可能就会运行的比较差。
  • 4.集中式系统被攻破的时候,影响一般不会很大。如果一个集群被攻破,那么他所有数据都有风险。

(三) 分布式的产品

分布式存储

  • 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的特例;节点可以篡改数据但不能伪造其他节点的数据。 特点:比上面的更严重,知道状态不知道原因,比如宕机等。 例子:比如内存、磁盘、网络错误,使数据发生位翻转,0变成了1。
  3. Performance failure(性能错误): 节点未在特定时间段内收到数据,即时间太早或太晚,或是处理慢了。特点:慢了还不如不用,直接切换或者降级来保证时效的决定比较正确。例子:网络节点形成不同的子集,子集中网络相通或不通
  4. Omission failure: 节点收到数据的时间无限晚,即收不到数据。特点:不知道状态或原因。例子:网络故障持续丢包、服务器断电
  5. Crash failure: 在omission failure的基础上,增加了节点停止响应的假设,也即持续性地omission failure。 特点:比上面的更严重,知道状态不知道原因,比如宕机等。 例子:服务器主板、板卡故障,引起死机短路等。
  6. Fail-stop failure: 在Crash failure的基础上增加了错误可检测的假设。 特点:错误码明确,知道状态和原因,比较好解决。 例子:磁盘故障,如 : 磁头不导道、盘片不转、磁介质损伤、坏道坏块。

Byzantine failure问题:

其中,最基础和经典的错误问题就是Byzantine failure(拜占庭将军问题)。拜占庭三个以上将军问题描述如下:拜占庭帝国(Byzantine Empire)军队的几个师驻扎在敌城外, 每个师都由各自的将军指挥. 将军们只能通过信使相互沟通. 在观察敌情之后, 他们必须制定一个共同的行动计划,以此统一行动 。

但是其中某一位或几位将军可能是叛徒,负责消息传递的信使也可能是叛徒, 他们可能篡改、伪造、丢失消息,企图破坏这一次统一行动。

所以他们之间必须有一个算法,使所有忠诚的将军能够达成一致,而且少数几个叛徒不能使忠诚的将军们做出错误的计划,即虽然部分叛变者可以传递虚假消息,但是不会影响忠诚的将军们投票做出正确的决策。该理论的结论是想容忍t个叛国者,必须增加t轮协商,并保证总将军个数大于3t。

拜占庭将军问题是分布式系统领域最复杂的容错模型, 它描述了如何在存在恶意行为(如消息篡改、伪造、丢失)的情况下使分布式系统达成一致,是我们理解分布式一致性协议和算法的重要基础。但是实际中很难解决这一问题,几乎是难以避免的,故我们课程所说的分布式系统都是假设不解决这一问题的,不考虑消息被篡改的系统。当前只有区块链和比特币解决这一问题。

故障模型案例表:

image.png

(二)共识和一致性

一般来说,数据一致性模型可以分为强一致性和弱一致性。强一致性也叫做线性一致性,除此以外,所有其他的一致性都是弱一致性的特殊情况。所谓强一致性,即复制是同步的,弱一致性,即复制是异步的。

最终一致性:

image.png

如图所示,某一时刻客户端A读到x=0,当客户端C正在写入时客户端A和B可能读到0或者1。当C写入A完成后,A可以读到1,但B仍为0。待经过一段时间后(几ms~几h都有可能),B也可以同步读到1。最终能读到一致的数据,称为Eventuallyconsistent (最终一致性)

当用户从异步从库读取时,如果此异步从库落后,他可能会看到过时的信息。 这种不一致只是一个暂时的状态——如果等待一段时间,从库最终会赶上并与主库保持一致。这称为最终一致性。

最终两个字用得很微妙,因为从写入主库到反映至从库之间的延迟,可能仅仅是几分之一秒,也可能是几个小时。

线性一致性:

image.png 如图所示,某一时刻客户端a收到x=1,然后客户端A将消息发送同步到其他的分布式客户端B和C,使各个客户端之间保持原子一致,这样就能通过客户端之间的互相协调,使客户端之间的原子同步。这是一种强一致性。

线性一致性(linearizability)是强一致性的一种,它主要由如下特征:

  • 任何一次读都能读到某个数据的最近一次写的数据
  • 系统中的所有进程,看到的操作顺序,都与全局时钟下的顺序一致
  • 在一个线性一致性的系统里面,任何操作都可能在调用或者返回之间原子和瞬间执行

(三)CAP理论

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

CAP理论往往运用于数据库领域,同样可以适用于分布式存储方向。

CA: 放弃分区容错性,加强一致性和可用性,其实就是传统的单机数据库的选择。

AP: 放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性。例如一些注重用户体验的系统,比如即时社交APP,知乎、贴吧、微博。

CP: 放弃可用性,追求一致性和分区容错性,例如与钱财安全相关的系统。所以就是银行金融类APP体验很差的原因吗???

故障转移示例图: image.png

近似解决方案,兼容一定的可用性和一致性。

首先我们将数据库的p1节点作为master节点,将p2节点作为备用节点backup。只有Master节点能作为写节点,backup只用来备份。 如图左边,Master接收到a=1的写入请求,然后立即同步到备用节点中。然后我们再读取,数据a这时从p1节点和p2节点读取都=1。如果p1宕机,master节点切换为p2继续提供服务。

如图右边,同步机制故障了,则master和其他点不能数据同步,则会丢失这一段时间写的数据。

(四)CAP理论

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

即把一个服务的多个数据库操作合并到一个事务中。如果这个事务提交成功,那么就全部执行,要么就全部回滚不执行。

数据库事务拥有四个特性ACID,即分别是原子性 (Atomicity) 、一致性(Consistency) 、隔离性 (lslation) 和持久性(Durability)

  • 原子性 (A)。原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
  • 一致性 (C)。指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行后都必须处于一致性状态。例子:比如a和b的总金额为100,A现在有50,b也有50。然后a给b转账20,那么a就有30,b就有70,那么他的总额还是100,还是保持在另一个一致性的状态。

注意:A和C必须保证,不然不是一个合格的数据库

  • 隔离性(I)。隔离性是当多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。这个是主要防止数据冲突覆写
  • 持久性(D) 。持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

(五)BASE理论

Base 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大型互联网分布式实践的总结,是基于 CAP 定理逐步演化而来的。对于大部分后端开发而言就够了,已经能够保证体验和可用就行了。

其核心思想是:

  • Basically Available(基本可用): 假设系统出现了不可预知的故障,但还是能用,相比较正常的系统而言存在响应时间上的损失或功能上的损失。需要优先保证!
  • Soft state(软状态):允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。重视体验而非中间状态。
  • Eventually consistent (最终一致性): 系统能保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值。

三 分布式事务

(一)二阶段提交

二阶段提交(Two-phase Commit): 为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法,也被称为一种协议,包括prepare阶段和commit阶段。

在我们的分布式系统中,每个节点虽然可以知道自己的操作成功或者失败,但是不知道其他的节点的成功或者失败,当一个事务跨越多个节点时,为了保持事务的ACID特性,需要引入一个作为协调者Coordinator的组件来统一掌控所有节点(称作参与者participater)的操作结果,并最终决定这些节点是否要进行真正的提交。

因此,如图所示,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈结果决定各参与者是否要提交操作还是回滚操作

image.png

image.png

(二 )三阶段提交

将两阶段提交中的Prepare阶段,拆成两部分CanCommit和和PreCommit机制。相比2PC,引入超时机制,减少了阻塞问题;增加了一个询问阶段,尽可能早的发现无法执行操作而需要中止的行为。但是,仍然存在数据不一致问题,在第三阶段如果只有一个参与者收到了abort操作指令,协调者和其他的参与者都会超时,协调者和参与者都继续提交事务,默认为成功,导致数据不一致。

image.png

(三)MVCC

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

时间戳的物理实现 :用GPS来实现,需要购买卫星的时间服务,我们服务器数据中心与truetime master交互,来获取时间。但是开始和结束阶段的请求+返回时间,会再增加2次+2次共4次通信,增加耗时和资源损耗。

时间戳的软件实现 :时间戳预言机 (TSO),采用中心化的授时方式,所有协调者向中心化节点获取时钟。优点是算法简单,实现方便,但需要每个节点都与他进行交互,会产生一些网络通信的成本。TSO的授时中就需要考虑低延迟,高性能以及更好的容错性。

四 Raft协议(重点!!)

(一)Raft概念

Raft协议是一种分布式一致性算法(共识算法),即使出现部分节点故障,网络延时等情况,也不影响各节点,进而提高系统的整体可用性。

Raft是使用较为广泛的分布式协议。一定意义上讲,RAFT也使用了Quorum机制。原因:raft遵循w+r>n这一原则,且因其领导者的概念优化了Quorum机制中需要的节点数量较大的问题。

(二)Raft协议中的成员身份

  • Leader - 领导者,通常一个系统中是一主 (Leader) 多从(Follower) 。Leader 负责处理所有的客户端请求,并向Follower同步请求日志,当日志同步到大多数节点上后,通知Follower提交日志
  • Follower - 跟随者,不会发送任何请求。接受并持久化Leader同步的日志,在Leader告知日志可以提交后,提交日志。当Leader出现故障时,主动推荐自己为Candidate。
  • Candidate - 备选者,Leader选举过程中的临时角色。向其他节点发送请求投票信息。如果获得大多数选票,则晋升为Leader

(三)Raft协议中的概念

  • Log (日志): 节点之间同步的信息,以只追加写的方式进行同步,解决了数据被覆盖的问题
  • Term (任期号) : 单调递增,每个Term内最多只有一个Leader (精髓!!解决了更换leader等复杂问题)
  • Committed: 日志被复制到多数派节点,即可认为已经被提交
  • Applied: 日志被应用到本地状态机: 执行了log中命令,修改了本机的内存状态

(四)Raft协议Leader选举过程

  • 1.初始全部为Follower
    1. Current Term + 1
  • 3.选举自己
  • 4.向其它参与者发起RequestVote请求,retry,直到以下情况:
  • 收到多数派请求,成为Leader,并发送心跳
  • 收到其它Leader的请求,转为Follower,更新自己的Term
  • 收到部分,但未达到多数派,选举超时,随机timeout开始下一轮
  • 5.遵循两个规则:在一个任期内每个参与者最多投一票 (持久化)要成为Leader,必须拿到多数投票

image.png

(五)Raft协议日志同步复制过程

新Leader产生,Leader和Follower不同步,Leader强制覆盖Followers的不同步的日志。回滚日志。

  1. Leader收到写请求w
  2. 将w写入本地log
  3. 向其它Follower发起AppendEntries RPC (和2是并行的)
  4. 等待多数派回复
  • Leader更新本地状态机,返回给客户端
  • 下一个心跳时通知Follower上一个Log已经被Committed了
  • Follower也根据命令更新本地状态机
  1. Follower有问题,Leader一直retry

(六) 切主(当leader有问题时):

当Leader出现问题时,就需要进行重新选举:

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

问题1: 老leader未失去身份,新leader已经选出,产生了“双主”该如何解决呢?

问题2:发生Leader切换,old leader收到了读请求。如果直接响应,可能会有Stale Read。如何解决?

以上两个问题解决方案思想都是保证读的强一致性:

1、读操作在lease timeout内,默认自己是leader;不是则发起一次heartbeat。等待Commit Index应用到状态机。

2、Election timeout > lease timeout: 新leader上任,自从上次心跳之后一定超过了Electiontimeout,l日leader大概率能够发现自己的Lease过期

3、一般来说需要等待2个tickline以上再重新选举,才能够保证不出现双主,即新王要等到旧王咽气才能登基