写在前面
已经大概三个月左右没有更新博客了,哈哈哈哈;
此博客是笔者在对《分布式系统原理介绍》进行概述,对于整个分布式系统协议的理解基于一些量化的指标考虑了数据的分布+副本协议(中心化/去中心化)进行了总结;
奥利给,继续干!!!!!!
注:本文不考虑拜占庭问题,即不存在中央节点;任何理论只能用于参考,实际解决方式还得靠自己
1 概念
1.1 模型
- 节点:一组逻辑的程序个体。
- 通信:通过 不可靠的网络进行节点间通信。
- 存储:存储数据,如果某个节点 A存储数据的方式是将数据通过网络发送到另一个节点 B,由节点 B 负责将数据存储到节点 B 的本地存储设备,那么不能认为节点 A 是有状态的节点,而只有节点 B 是有状态的节点。
- 异常:机器宕机,网络异常(消息丢失、消息乱序、数据错误、不可靠的TCP协议),RPC三态(成功、失败、超时),存储数据丢失,其他异常…
处理异常的黄金原则:被大量工程实践所检验过的异常处理黄金原则是:任何在设计阶段考虑到的异常情况一定会在系统实际运行中发生,但在系统实际运行遇到的异常却很有可能在设计时未能考虑,所以,除非需求指标允许,在系统设计时不能放过任何异常情况。工程中常常容易出问题的一种思路是认为某种异常出现的概率非常小以至于可以忽略不计。这种思路的错误在于只注意到了单次异常事件发生的概率,而忽略了样本的大小。
1.2 副本
副本指在分布式系统中为数据或者服务提供的冗余,副本协议是贯穿整个分布式系统的理论核心。例如,GFS 系统的同一个 chunk 的数个副本就是典型的数据副本,而 Map Reduce 系统的 Job Worker 则是典型的服务副本。
注:这里服务副本的概念非常有意思。
副本一致性:分布式系统通过副本控制协议,使得系统外部读取系统内部各个 副本的数据在一定的约束条件下相同。副本一致性是针对分布式系统而言的,不是针对某一个副本而言。一致性(consistency)包括强一致性、最终一致性、弱一致性。
1.3 衡量分布式系统的指标
- 性能:吞吐量、延迟、并发能力(QPS)
- 可用性:遇到异常可以正确提供服务的能力
- 可扩展性:分布式系统因此产生的特性
- 一致性:增加可用性,引入副本,引出副本一致性问题。
2 分布式系统原理
首先要解决的就是如何将问题拆解为可以使用多机分布式解决,使得分布式系统中的每台机器负责原问题的一个子集。
2.1 数据分布方式
数据分布方式 | 优点 | 缺点 | 应用 |
---|---|---|---|
哈希方式 | 散列性好,元信息=哈希函数+服务器总数 | 扩展性不高,扩展集群,数据需要重新分布;特征不明显,容易hash倾斜 | Big Pipe |
按数据范围分布 | 比hash灵活,可以拆分原有分区 | 分区多,元数据规模大 | 瓶颈在于元数据服务器规模要求大,一般少用,如Big Table,HBase |
按数量分布 | 按照数据块(chunk)分布,不会造成数据倾斜 | 同理,元数据的数据量大,管理麻烦 | GFS&HDFS |
一致性哈希(最早应用于P2P网络) | 一个节点异常,压力转移到相邻节点,新增节点只能分摊相邻压力 | 引入虚节点解决上述问题,Dynamo&Cassandra |
2.2 基本副本协议
副本控制协议要具有一定的对抗异常状态的容错能力,从而使得系统具有一定的可用性,同时副本控制协议要能提供一定一致性级别。
中心化(centralized)副本控制协议:Primary-secondary 类型的协议一般要解决四大类问题:数据更新流程、数据读取方式、Primary副本的确定和切换、数据同步(reconcile)。primary数据更新的压力可以通过P2P的方式分摊给其他的secondary节点;数据读取面临一致性的压力,可以通过中心元数据管理系统,记录哪些副本可用,哪些副本不可用,但是降低了系统的可用性;节点异常,系统需要探测时间,期间系统不能提供更新服务,如果只能读primary副本,则无法提供读服务;数据同步可以通过日志的方式或者从primary节点copy数据。
注:日志在哪里都是个好东西。
去中心化(decentralized)副本控制协议:优点在于民主,主节点异常不会导致系统受到加大影响;缺点是过程复杂,效率低;paxos是唯一在工程中得到应用的强一致性去中心化副本控制协议。
工程投影:
Primary-Secondary 协议:GFS、Big Pipe
Paxos协议:Chubby和zookeeper通过去中心协议选出primary节点,完成选举后,这两个系统都转为中心化的副本控制协议。
2.3 Lease机制
Lease机制定义:Lease是由颁发者授予的在某一有效期的承诺。颁发者一旦发出Lease,则无论接收方是否收到,也无论后续接收方处于何种状态,只要Lease不过期,颁发者一定验收承诺;接收方在Lease的有效期内可以使用颁发者的承诺,一旦Lease过期,接收方一定不能继续使用颁发者的承诺。
Lease机制的最重要的应用:判定节点状态。
2.3.1 基于Lease机制确定节点状态
举例说明:在一个primary-secondary的架构中,三个节点A、B、C互为副本,其中有一个节点primary,且同一时刻只能有一个primary节点。另外一个节点Q负责判断节点A、B、C的状态,一旦Q发现primary异常,则节点Q需要选择另一个节点为primary。假设最开始时节点A为primary,B、C为secondary。
解法1:基于心跳机制。节点A、B、C周期性的给Q发送心跳信息,如果Q超过一定时间接收不到某个节点的心跳则认为改节点异常。
存在的问题:在工程实践中,节点A和节点Q之间的网络拥塞可能会造成“瞬断”,瞬断是可以恢复的。Q节点本身如果异常,则可能导致A节点的心跳延迟,以至于节点Q认为节点A没有发送心跳。这种情况下Q可能会再次选择其他节点作为主节点,从而产生“双主”问题。
注:上述的分布式协议依赖于节点状态认知的全局一致性,那么换句话说,如果全局一直性是全体协商后的结果,那么按照去中心化的思想可以实现。
解法2 :基于Lease机制。节点A、B、C依旧周期性的向Q汇报自己的状态,Q收到心跳信号后发送一个Lease,表示确定了A、B、C的状态,并允许在Lease有效期内正常工作。Q给primary节点发送一个特殊的Lease,表示其可以作为primary节点工作。【一旦节点Q希望切换新的primary,则需要等前一个primary的Lease过期】,则可以颁发新的Lease给新的primary节点。
存在问题:一旦中心节点Q发生异常,那么所有的节点没有Lease,因此,实际系统总是使用多个中心节点互为副本,刑场小的集群,对外颁发Lease。如,zookeeper
注:这里是Q节点根据Lease的机制,可以主动选择是否切换节点。
问题:Lease的有效期时间选择?
工程中,常选择的Lease时长是10秒级别,这是一个经过验证的验证值。
2.3.2 工程投影
zookeeper的secondary节点(follower)并不向primary节点(leader)发送Lease,zookeeper首先通过Paxos选举,得到primary和secondary节点。与chubby类似的是,zookeeper中的primary节点会像Client颁发Lease,Lease的时间是zookeeper中的session时间。在zookeeper中,临时节点是与session的生命期绑定的,当一个Client的session超时,那么这个Client创建的节点会被zookeeper自动删除,通过监听临时节点的状态,也很容易的实现对节点状态的监控。
在工程上,很多地方都间接的在使用Lease,借助zookeeper,我们可以简单的实现高效的、无单点选主、状态监控、分布式锁、分布式消息队列等功能,实际上,这些功能的实现依赖于背后zookeeper与Client之间的Lease。
2.4 Quorum机制
Quorum机制是一种简单有效的副本管理机制。
为了简化讨论,本节约定:Write是一系列顺序的过程,通过其他机制确定更新操作的顺序(例如primary-secondary架构中由primary决定顺序);
1、记每个更新操作位wi,i为更新操作单调递增的序号,每个wi执行成功后副本数据都发生变化,称为不同的数据版本,记作vi;
2、假设每个副本都保存了历史上所有版本的数据。
2.4.2 Write-all-read-one
Write-all-read-one是一种最简单的副本控制规则,即,更新的时候,在所有副本上都更新成功,才认为是更新成功,从而保证所有副本的一致,这样在读取数据的时候可以读任一副本上的数据。
根据WARO的约定,当某次更新操作wi一旦在所有的N个副本中都能成功,则全局都能感知到这个信息,此后读取数据的版本为vi,则称这次操作为“成功提交的更新操作”。
在工程实践中,这种机制往往比较难实现或效率低下,副本之间需要时刻保证相互信息的一致性;很自然的,我们想到把版本信息放到某组元数据服务器上。但是,如果更新比较频繁,那么记录更新成功的版本号vi的操作将成为一个关键操作,容易成为瓶颈。由于为了强一致性,那么在读取数前必须读取元数据中的版本号,在大压力下也容易因为元数据服务器的性能造成瓶颈。
注:虽然WARO读服务的可用性高,但是更新服务的可用性不高,虽然使用了副本,但是需要在N个副本上都成功才行,因此更新服务的可用性等效于没用副本。
2.4.3 Quorum定义
WARO牺牲了更新服务的可用性,最大程度的增强读服务的可用性。其实,Quorum的本质就是对WARO的条件进行了松弛。
举例:某系统有5个副本,W=3,R=3,最初5个副本的数据一致,都是v1,某次更新操作w2在前3个副本上成功,副本情况变成(v2,v2,v2,v1,v1)。此时,任意3个副本的组合中一定包括v2。
(W=N,R=1)就得到WARO,即WARO是Quorum机制的一种特例。
总结:
1、仅仅依赖Quorum机制是无法保证强一致性的。因为仅有Quorum机制时无法确定最新已提交的版本号,除非将最新已提交的版本号作为元数据由特定的元数据服务器或者元数据集群管理,
否则很难确定最新成功提交的版本号。
2、Quorum机制的三个系统参数N、W、R控制了系统的可用性,也是系统对用户承诺:数据最多有N个副本,但数据更新成功W个副本即返回用户成功。对于一致性要求较高的Quorum系统,系统还应该承诺任何时候不读取未成功提交的数据,即读取到的数据都是曾经在W个副本上成功的数据。
假定在没有元数据服务器的情况下,为了实现强一致性,可以尝试增强以下条件:
1、限制提交的更新操作必须严格递增,从而成功提交的数据版本号必须是连续增加的。
2、如果读取到的有效副本数不足W个,就继续读取其他副本,直到成功读取W个改版本的副本,如果还是不满足,则使用R中版本号第二大的为罪行的成功提交的版本…
注:在上面的这个改造过程中,我们可以发现,不同的机制本身并没有决定的完美,核心需要关注应用方向,优化方向......,去中心化的Quorum更新机制在工程实践中也很少用到
2.4.6 工程投影
zookeeper使用的Paxos协议本身就是利用了Quorum机制,当利用Paxos协议选出primary后,zookeeper的更新流量由primary节点控制,每次更新澳洲,primary节点只需要更新超过半数的节点后就返回用户成功。每次更新操作都会递增各个节点的版本号(xzid)。当primary节点异常,利用Paxos协议选举新的primary时,每个节点都会以自己的版本号发起Paxos提议,从而保证了选出的新primary是某个超过半数副本集合中版本号最大的副本。
2.5 日志技术
日志技术是宕机回复的主要技术之一。日志技术最初使用在数据库系统重。严格来说日志技术不是一种分布式系统的技术,但在分布式系统的实践中,却广泛使用了日志技术来做宕机恢复,甚至如BIGTable等系统将日志保存到一个分布式系统重进一步增强了系统的容错能力。
注:似乎日志可以用很多用途,核心可能需要考虑用户记录信息???
数据库的日志主要分为Undo Log、Redo Log、Redo/Undo Log与No Redo/No Undo Log。
2.5.2 Redo Log
问题模型:假设需要设计一个高速的单机查询系统,将数据全部存放在内存中以实现高速的数据查询,每次更新操作更新一小部分数据(类似redis),现在问题为利用日志技术实现该内存查询系统的宕机恢复
。与数据库的事务不同的是,这个问题模型中的每个成功的更新操作都会生效。这也等效为数据库的每个事务只有一个更新操作,且每次更新操作都可以也必须立即提交(auto commit)。
Redo Log更新流程:
1、更新操作的结果以append否方式写入日志文件
2、按更新操作修改内存中的数据,set k1=1
3、返回更新成功
Redo Log宕机恢复:
1、从头读取日志文件中的每次更新操作的结果,用这些结果修改内存中的数据。
2.5.3 Checkpoint
宕机恢复流量的缺点是需要回放所有Redo日志,效率低;
解决这一问题的方式可以通过Checkpoint实现,Checkpoint技术的过程即将内存中的数据以某种易于重新加载的数据组织方式完整的dump到磁盘,从而减少宕机恢复时需要回放的日志数据。
注:对于Checkpoint的具体使用方式,这里不做过多说明,实际上运用需要学会灵活转变具体的流程,这里只是表示一种大体方式。
2.5.4 工程投影
在zookeeper中,数据完全保存在内存中,更新日志不断持久化到磁盘;为了实现快速的宕机恢复,zookeeper周期性的将内存数据以Checkpoint的方式dump到磁盘。
mysql的主从库设计也是基于日志。从库只需通过回放主库的日志,就可以实现与主库的同步。由于从库同步的速度与主库更新的速度没有强约束,这种方式只能实现最终一致性。
2.6 两阶段提交协议
两阶段提交协议是一种经典的强一致性中心化副本控制协议。实际工程中,该协议存在较多问题,但研究该协议能很好的理解分布式系统的几个典型问题。
2.6.1 问题背景
在经典的分布式数据库模型中,同一个数据库的各个副本运行在不同的节点上,每个副本的数据要求完全一致。
数据库中的操作都是事务(transaction),一个事务是一系列读、写操作,事务满足ACID;每个事务的最终状态要么是提交(commit),要么是失败(abort);一旦一个事务成功提交,那么这个事务中所有的写操作成功,否则所有的写操作都失败。
核心思想: 1、第一阶段,协调者询问所有的参与者是否可以提交事务(请参与者投票),所有参与者向协调者投票。 2、第二阶段,协调者根据所有参与者的投票结果做出是否事务可以全局提交的决定,并通知所有参与者执行该决定。 两阶段提交协议的可以全局提交的前提是所有的参与者都同意提交事务,只要有一个参与者投票选择放弃(abort)事务,则事务必须被放弃。
2.6.2 协议分析
两阶段提交协议在工程实践中真正使用的较少,主要原因有以下几点:
第一、两阶段提交协议的容错能力较差。
两阶段提交协议在某些情况下存在流程无法执行下去的情况,且也无法判断流程状态。好的分布式协议往往总是可以在即使发生异常的情况下也能执行下去,如:Lease服务器节点总是可以通过时间判定出Lease是否有效;
注:感觉Flink的Checkpoint存在过期时间就是对最简单的两阶段提交进行了改造;
第二、两阶段提交协议的性能较差。
一次成功的两阶段提交协议流程中,至少要两轮交互4个消息。另一方面,协调组需要等待所有的参与者的投票结果,一旦存在较慢的参与者,会影响全局流程执行速度。
注:其实也不是绝对的慢,核心看用户关注什么,Flink在ck的时候,数据仍然可以处理......
2.7 基于MVCC的分布式事务
MVCC技术最初也是在数据库系统中被提出,但这种思想并不局限于单机的分布式系统,在分布式系统中同样有效。
MVCC即多个不同版本的数据实现并发控制技术,其基本思想是为每次事务生成一个新版本的数据,在读数据时不同版本的数据即可实现对事务结果的完整性读取。
MVCC过程非常类似SVM等版本控制系统的流程,或者说SVN等版本控制系统就是使用的MVCC思想。
2.7.1 应用场景
在Doris中,数据按批量进行更新,每个批量的数据都可以认为是一个事务,必须同时原子性的生效。Doris将每条数据附带了一个导入的版本号,在读取数据时元数据中已生效的版本号与数据上的导入版本号做过了,从而不读取正在更新的尚未生效的数据,实现了分布式事务更新。
2.8 Paxos协议
2.8.1 简介
Paxos协议是少数在工程实践中证实的强一致性、高可用的去中心化分布式协议。
Paxos协议的流程较为复杂,但其基本思想却不难理解,类似于人类社会的投票过程。Paxos协议中,有一组完全对等的参与节点(称为accpetor),这组节点各自就某一事件做成决议,如果某个决议获得了超过半数节点的同意则生效。Paxos协议中只要超过一半的节点正常,就可以工作,能很好对抗宕机、网络分化等情况。
2.8.2 工程投影
zookeeper中总共zxid将两个场景较好的结合起来,且能保证全局的强一致性。由于同一时刻只有一个zookeeper节点能获得超过半数的follower,所以同一时刻最多只能存在唯一的leader;每个leader利用fifo以zxid的顺序更新各个follower,只有成功完成前一个更新操作的才会进行下一个更新操作,在同一个leader任期内,数据在全局满足Quorum约束的强一致,即读超过半数的节点一定可以读到罪行已提交的数据;每个成功的更新操作都至少被超过半数的节点确认,是的新选举的leader一定可以报考罪行的已成功提交的数据。
2.9 CAP理论
2.9.1 定义
CAP理论的定义很简单,CAP三个字母分别代表了分布式系统中三个相互矛盾的属性:
1、consistency(一致性):CAP理论中的副本一致性特指强一致性;
2、Availiablity(可用性):指系统在出现异常时已经可以提供服务;
3、Tolerance to the partition of nerwork(分区容忍):指系统可以对网络分化这种异常情况进行容错处理;(多副本)
证明:不存在CAP兼具的系统;
假设系统只有两个副本A和B,client更新这两个部分;
假设在网络分化时,client可以与副本A正常通信,但副本B与client、副本B与副本A无法通信==>即,client对副本A的更新信息永远无法同步到副本B上;
===>如果希望系统依旧具有强一致的属性,则此时需要停止更新服务,即不能修改数据,从而是的A和B保持一致;
===>如果希望系统依旧可以提供更新服务,则只能更新副本A而无法更新副本B,此时无法保证副本A与副本B一直;
2.9.2 协议分析
1、Lease机制:Lease机制牺牲了部分异常情况下的A,从而获得了完全的C和很好的P;
Lease机制中,primary副本节点宕机后,只有待Lease超时才能选出新的服务,这段时间由于缺乏primary部分是没有更新服务的;
注:主节点宕机,即无法对外提供服务
2、Quorum机制:总共有N个服务,成功更新W个副本则算成功提交,读取时读R个副本;
这种一般的Quorum机制,在CAP三大因素中都各做了折中,有一定的C,有较好的A,也有较好的P,是一种较为平衡的分布式协议;
3、两阶段提交协议:两阶段提交系统具有完全的C,很糟糕的A,很糟糕的P;
两阶段提交协议保证了副本间是完全一致的,这也是协议的设计目的;再者,协议在一个节点出现异常时,就无法更新数据,其服务可用性较低;最后,一旦协调者与参与者之间网络分化,则无法提供服务;
注:很明显,不同的协议针对不同的应用场景,即使根据不同场景决定容忍度
4、Paxos协议:Paxos协议具有完全的C,较好的A,较好的P;Paxos的A与P的属性与Quorum机制类型,因为Paxos的协议本身就就有Quorum机制的因素;
Paxos协议是一种强一致性协议;再者,Paxos协议只有两种情况下服务不可用:一是查过半数的proposer异常,二是出现活锁;
前者可以通过增加proposer的个数来降低由于proposer异常影响服务的概率,后者本身发生的概率就极低
最后,只要能与超过半数的proposer通信就可以完成协议流程,协议本身具有较好的容忍分区的能力;