分布式系统以及共识机制

本文分为4个部分。第一部分讲解分布式系统重要的基本概念和理论,第二部分讲解拜占庭将军问题,第三部分讲解传统分布式共识机制,最后一部分讲解区块链里的共识机制。

Part 1 分布式系统的基本概念和重要理论


分布式系统是用计算机集群解决问题。

1.1 CAP Theorem:

CAP 原理是由 Eric Brewer 2000年时在ACM组织的一个研讨会上面提出的猜想,后来被证明。被认为是分布式系统领域的重要原理。

C 是指 Consistency(一致性):
所有节点在同一个时间看到的数据是完全相同的。假设有两个节点,节点 A 与节点 B。当我们往节点 A 完成写入数据操作后,节点 B 随之可以读取到相应最新的数据。

A 是指 Availability(可用性):
要求在有限的时间内,任何非失败的节点都能应答请求。

P 是指 Partition Tolerance(分区容忍性):
即使出现信息丢失,网络或者节点失败,系统仍然能保持运作。

CAP 原理表明在分布式系统里,无法同时实现3个特性,只能弱化其中一个而实现另外两个特性。
因此要分实际的应用场景去看待这个问题。

CAP

同时具备 CAP 三种的系统是不存在的,因此可分为三种系统类型:

CA (一致性 + 可用性),比如完全严格的Quorum协议,例如两阶段提交。
CP (一致性 + 分区容错性),比如 Paxos,Raft。
AP (可用性 + 分区容错性), 比如使用冲突解决方案的协议,Dynamo。

CA 和 CP 系统设计都提供相同的一致性模型: 强一致性。唯一的区别是 CA 系统不能容忍任何节点故障; 一个CP系统在非拜占庭故障模型中可以容忍多达 2f + 1 个节点的故障(换句话说,只要多数 f + 1 保持不变,它就可以容忍少数节点 f 的故障)。 原因很简单:

CA 系统不区分节点故障和网络故障,因此必须停止接受各处的写入操作以避免引入分歧(多个副本)。 它不能分辨出远程节点是否关闭,或者只是网络连接是否中断: 因此唯一安全的做法就是停止接受写入。

CP 系统通过强制分区两侧的不对称行为来防止分歧(例如,保持单一副本一致性)。 它只保留大部分分区,并且要求少数分区变得不可用(例如停止接受写入),这保留了一定程度的可用性(大部分分区),并且仍然确保单拷贝一致性。

重要的是,CP 系统将网络分区合并到他们的故障模型中,并使用像Paxos,Raft 或 viewstamped 的复制等算法来区分多数分区和少数分区。 CA 系统不具备分区感知能力,并且历史上更常见,它们通常使用两阶段提交算法,在传统分布式关系数据库中很常见。

Part 2 拜占庭将军问题


拜占庭将军问题,讨论的是允许存在少数不诚实节点(作恶,伪造消息)的场景下达成一致性的问题。
这个问题用文字来表达是很难描述清楚的,因此推荐大家看这个视频 Byzantine Fault Tolerance 来了解这个问题。看完这个视频,相信你一定会对拜占庭问题有个整体清晰的概念。
总的来说,就是当叛变者不超过 3分之1时,存在有效的算法,不论叛变者怎么折腾搞破坏,忠诚的将军们总能达到一致的结果。
用数学公式来表达就是,假设节点总数为 N, 叛变将军数为 F, 当 N >= 3F + 1,问题就有解。
Byzantine Fault Tolerant (BFT) 算法就是解决这个问题的。

Part 3 分布式一致性共识机制


1. Paxos

1.1 Paxos算法背景

Paxos算法是Lamport宗师提出的一种基于消息传递的分布式一致性算法,使其获得2013年图灵奖。

Paxos由Lamport于1998年在《The Part-Time Parliament》论文中首次公开,最初的描述使用希腊的一个小岛Paxos作为比喻,描述了Paxos小岛中通过决议的流程,并以此命名这个算法,但是这个描述理解起来比较有挑战性。后来在2001年,Lamport觉得同行不能理解他的幽默感,于是重新发表了朴实的算法描述版本《Paxos Made Simple》。

自Paxos问世以来就持续垄断了分布式一致性算法,Paxos这个名词几乎等同于分布式一致性。Google的很多大型分布式系统都采用了Paxos算法来解决分布式一致性问题,如Chubby、Megastore以及Spanner等。开源的ZooKeeper,以及MySQL 5.7推出的用来取代传统的主从复制的MySQL Group Replication等纷纷采用Paxos算法解决分布式一致性问题。

然而,Paxos的最大特点就是难,不仅难以理解,更难以实现。

1.2 Paxos算法流程

Paxos算法解决的问题正是分布式一致性问题,即一个分布式系统中的各个进程如何就某个值(决议)达成一致。

Paxos算法运行在允许宕机故障的异步系统中,不要求可靠的消息传递,可容忍消息丢失、延迟、乱序以及重复。它利用大多数 (Majority) 机制保证了2F+1的容错能力,即2F+1个节点的系统最多允许F个节点同时出现故障。

一个或多个提议进程 (Proposer) 可以发起提案 (Proposal),Paxos算法使所有提案中的某一个提案,在所有进程中达成一致。系统中的多数派同时认可该提案,即达成了一致。最多只针对一个确定的提案达成一致。

Paxos将系统中的角色分为提议者 (Proposer),决策者 (Acceptor),和最终决策学习者 (Learner):

  • Proposer: 提出提案 (Proposal)。Proposal信息包括提案编号 (Proposal ID) 和提议的值 (Value)。
  • Acceptor:参与决策,回应Proposers的提案。收到Proposal后可以接受提案,若Proposal获得多数Acceptors的接受,则称该Proposal被批准。
  • Learner:不参与决策,从Proposers/Acceptors学习最新达成一致的提案(Value)。

在多副本状态机中,每个副本同时具有Proposer、Acceptor、Learner三种角色。

Paxos中的角色

Paxos算法通过一个决议分为两个阶段(Learn阶段之前决议已经形成):

  1. 第一阶段:Prepare阶段。Proposer向Acceptors发出Prepare请求,Acceptors针对收到的Prepare请求进行Promise承诺。
  2. 第二阶段:Accept阶段。Proposer收到多数Acceptors承诺的Promise后,向Acceptors发出Propose请求,Acceptors针对收到的Propose请求进行Accept处理。
  3. 第三阶段:Learn阶段。Proposer在收到多数Acceptors的Accept之后,标志着本次Accept成功,决议形成,将形成的决议发送给所有Learners。
Paxos算法中的流程

Paxos算法流程中的每条消息描述如下:

  • Prepare: Proposer生成全局唯一且递增的Proposal ID (可使用时间戳加Server ID),向所有Acceptors发送Prepare请求,这里无需携带提案内容,只携带Proposal ID即可。
  • Promise: Acceptors收到Prepare请求后,做出“两个承诺,一个应答”。

两个承诺:

  1. 不再接受Proposal ID小于等于(注意:这里是<= )当前请求的Prepare请求。

  2. 不再接受Proposal ID小于(注意:这里是< )当前请求的Propose请求。

一个应答:

不违背以前作出的承诺下,回复已经Accept过的提案中Proposal ID最大的那个提案的Value和Proposal ID,没有则返回空值。

  • Propose: Proposer 收到多数Acceptors的Promise应答后,从应答中选择Proposal ID最大的提案的Value,作为本次要发起的提案。如果所有应答的提案Value均为空值,则可以自己随意决定提案Value。然后携带当前Proposal ID,向所有Acceptors发送Propose请求。
  • Accept: Acceptor收到Propose请求后,在不违背自己之前作出的承诺下,接受并持久化当前Proposal ID和提案Value。
  • Learn: Proposer收到多数Acceptors的Accept后,决议形成,将形成的决议发送给所有Learners。

Paxos算法伪代码描述如下:

Paxos伪代码
  1. 获取一个Proposal ID n,为了保证Proposal ID唯一,可采用时间戳+Server ID生成;
  2. Proposer向所有Acceptors广播Prepare(n)请求;
  3. Acceptor比较n和minProposal,如果n>minProposal,minProposal=n,并且将 acceptedProposal 和 acceptedValue 返回;
  4. Proposer接收到过半数回复后,如果发现有acceptedValue返回,将所有回复中acceptedProposal最大的acceptedValue作为本次提案的value,否则可以任意决定本次提案的value;
  5. 到这里可以进入第二阶段,广播Accept (n,value) 到所有节点;
  6. Acceptor比较n和minProposal,如果n>=minProposal,则acceptedProposal=minProposal=n,acceptedValue=value,本地持久化后,返回;否则,返回minProposal。
  7. 提议者接收到过半数请求后,如果发现有返回值result >n,表示有更新的提议,跳转到1;否则value达成一致。

下面举几个例子,实例1如下图:

Paxos算法示例1

图中P代表Prepare阶段,A代表Accept阶段。3.1代表Proposal ID为3.1,其中3为时间戳,1为Server ID。X和Y代表提议Value。

实例1中P 3.1达成多数派,其Value(X)被Accept,然后P 4.5学习到Value(X),并Accept。

Paxos算法示例2

实例2中P 3.1没有被多数派Accept(只有S3 Accept),但是被P 4.5学习到,P 4.5将自己的Value由Y替换为X,Accept(X)。


Paxos算法示例3

实例3中P 3.1没有被多数派Accept(只有S1 Accept),同时也没有被P 4.5学习到。由于P 4.5 Propose的所有应答,均未返回Value,则P 4.5可以Accept自己的Value (Y)。后续P 3.1的Accept (X) 会失败,已经Accept的S1,会被覆盖。

Paxos算法可能形成活锁而永远不会结束,如下图实例所示:


Paxos算法示例4

回顾两个承诺之一,Acceptor不再应答Proposal ID小于等于当前请求的Prepare请求。意味着需要应答Proposal ID大于当前请求的Prepare请求。

两个Proposers交替Prepare成功,而Accept失败,形成活锁(Livelock)。

1.3 Multi-Paxos算法

原始的Paxos算法(Basic Paxos)只能对一个值形成决议,决议的形成至少需要两次网络来回,在高并发情况下可能需要更多的网络来回,极端情况下甚至可能形成活锁。如果想连续确定多个值,Basic Paxos搞不定了。因此Basic Paxos几乎只是用来做理论研究,并不直接应用在实际工程中。

实际应用中几乎都需要连续确定多个值,而且希望能有更高的效率。Multi-Paxos正是为解决此问题而提出。Multi-Paxos基于Basic Paxos做了两点改进:

  1. 针对每一个要确定的值,运行一次Paxos算法实例(Instance),形成决议。每一个Paxos实例使用唯一的Instance ID标识。
  2. 在所有Proposers中选举一个Leader,由Leader唯一地提交Proposal给Acceptors进行表决。这样没有Proposer竞争,解决了活锁问题。在系统中仅有一个Leader进行Value提交的情况下,Prepare阶段就可以跳过,从而将两阶段变为一阶段,提高效率。
Multi-Paxos流程

Multi-Paxos首先需要选举Leader,Leader的确定也是一次决议的形成,所以可执行一次Basic Paxos实例来选举出一个Leader。选出Leader之后只能由Leader提交Proposal,在Leader宕机之后服务临时不可用,需要重新选举Leader继续服务。在系统中仅有一个Leader进行Proposal提交的情况下,Prepare阶段可以跳过。

Multi-Paxos通过改变Prepare阶段的作用范围至后面Leader提交的所有实例,从而使得Leader的连续提交只需要执行一次Prepare阶段,后续只需要执行Accept阶段,将两阶段变为一阶段,提高了效率。为了区分连续提交的多个实例,每个实例使用一个Instance ID标识,Instance ID由Leader本地递增生成即可。

Multi-Paxos允许有多个自认为是Leader的节点并发提交Proposal而不影响其安全性,这样的场景即退化为Basic Paxos。

Chubby和Boxwood均使用Multi-Paxos。ZooKeeper使用的Zab也是Multi-Paxos的变形。

Part 4 区块链里的共识机制


1.1 POW

PoW 是Proof of Work 即工作量证明,目前运用在比特币与以太坊区块链,通过解答数学问题来实现。
请看我之前的一篇用Go语言实现的带工作量证明的区块链
跟着实现一遍,就会对 PoW 有一个非常清晰的理解。

1.2 POS

PoS 是权益证明,即通过节点所拥有的代币数量来获得争取生成区块的权利。比起 PoW, PoS的优点是在于不用浪费那么多计算资源,电力能源去解答数学问题来争取生成区块的权力。但是缺点是容易导致生成区块权利的中心化,比如代币数量多的人,永远都拥有很高的概率获得生成区块的权利。

1.3 DPOS

DPoS 是代理权益证明,假设某个区块链有120个节点,那会选出20个节点来作为代理节点,即只有这20个节点拥有生成新区块的权力。他们会轮流去生成新的区块。DPoS的优点是提高了区块链的TPS,代理节点只有20个,那么效率肯定会高很多。缺点是这些代理节点都是通过投票产生,那当有人或者组织控制多数的投票权时,就相当与控制了整个区块链了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容