分布式理论演化

目录

前言

练习,思考只是手段,内在联系才是目的。

经过这次秋招,我得到了很多的收获,其中最大的收获是让我领悟到了什么是「正确」的学习方法。

在写之前,大家可以回忆下,当你向大佬去请教如何才能学的更好的时候,得到的答案大多是「多做,多想」。但是有时候这么做之后,效果并没有那么的好。

这里举一个具体的case,今年在阿里暑期实习的时候,带我的师兄真的很好很负责任,在设计方案的时候,总会让我先提出方案,然后指出我的不足。可往往我没有师兄想的那么全面,他说出答案的时候,这些我基本都或多或少的听过,可是我就是没有办法把场景和最佳的解决方案给放到一块,师兄也是告诉我要多想,有一次实在忍不住告诉了师兄我的疑惑,和师兄交流后发现是我学技术的时候过于关注API的使用,而对技术的演化,解决的问题,技术之前的对比没有关注。这就导致我虽然也投入了巨大的精力,也去「思考」了,但是却没有收获。

在我们的学习工作生活中,我们肯定会遇到某些场景中的一些问题?那么为了解决这些问题,我们提出了方法1,2,3。方法1解决了场景中的一部分问题,方法2解决了另外一部分问题。那么这个时候我们是不是要把方法1和方法2进行对比,其联系是什么,区别是什么?接下来,肯定还会提出新的方法3,方法3可能综合了方法1和方法2的优点,但是也可能会带来新的问题。没有一种方案是完美无缺的,当我们理清楚这些方案之间的区别,演化过程的时候,我们可以对其进行抽象出一套方法论,在相似的场景中,我们可以进行迅速的迁移。

当然了上面这一段话是非常抽象,难以理解的,我们的大脑是习惯性的喜欢具体,厌恶抽象的。下面我会以分布式理论的演化过程来具体说明一下,希望可以借助这个例子来进行说明。

从中心化到分布式

最开始的时候,计算机还是还是高端玩家的东西,使用人数,计算量,存储量都比较小。虽然计算机价格的下降,个人计算机取得了快速的发展,这给服务器带来了巨大的压力。

面对这么一个情况,不同的人提出了不同的方案,以IBM为首的厂家提出了大型机的概念,拼命的给电脑加CPU,内存,但是价格也是拼命的上涨,在国内,基本上只有银行才可以消费的起。于此同时,另外一群大佬,提出了分布式的概念,一个电脑无法完成的任务,让多台电脑进行协同工作。

先来看分布式系统的基本性质:状态复制。所有的节点以相同的顺序执行一个命令序列。我们由状态机的理论可知,初始状态相同,输入相同,那么输出也是相同的。

我们还需要出入一下分布式中的一个重要的CAP原理:

  • 一致性( Consistency):指的是强一致性;
  • 可用性( Availablity):服务一直可用,而且是正常响应时间;
  • 分区容忍性( Partition):分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。

作为分布式,P是必须满足的,所以一般是在C和A之间做出权衡。

现在我们知道,要让分布式系统运作,需要一个节点来分发命令。这里就引出了串行化器的概念。

单个服务器称为串行化器,用来进行分发命令,实现状态复制。也被称为主从复制(Master-Slave Replication)。由于只使用了一个串行化器,在某些节点出现宕机或者网络状态较差的时候,可能会出现执行结果不一致的问题,此外,还存在单点故障(Single Point of Failure)的问题。我们也称之为1PC。

为了解决串行化器的问题,我们提出了两阶段提交协议。

  • 在准备阶段,协调者会向所有参与者询问“是否可以执行提交”操作,同时会开始等待各参与者节点回复。
  • 在提交阶段,当所有参与者都回复“同意”时,协调者会向所有节点发出“正式提交”操作请求。如果有节点不同意或者超时,所有节点回滚,否则,提交。

image-20201127114045146

还是有问题的,事务的提交的过程中节点是处于阻塞状态的,节点在等待其他节点返回时无法响应其他服务。并且如果出现参与者宕机或者无响应时,协调者需要通过超时机制来恢复,系统无法容错且低效。

Paxos

两阶段提交协议最大的问题是需要所有的节点都正常工作,这个要求太苛刻了,所有我们提出了Paxos算法,其不需要所有的节点都正常工作,半数以上就可以了。本质是为了解决效率的问题,而不是一致性的问题

Paxos把节点分为以下几种类型:

  • 提议者(Proposer): Proposer 负责提出提案,包括提案标号和提案内容。
  • 决策者(Acceptor):参与提案的决策,Acceptor收到提案后会根据情况决策是否要接受提案,若足够多的Acceptor接受提案,则该提案3通过。
  • 决策学习者(Learner):不参与提案的提出或者决策过程,Proposer收到足够多的Acceptor同意后,会将通过的决议发送给所有的Learner。

准备阶段(Prepare):Proposer选择一个提案标号Proposer ID并将prepare消息发送给Acceptors中的一个多数;Acceptor收到Prepare的消息后,如果提案标号大于它接受的所有历史提案的标号,就回复接受,并承诺不再接受提案标号小于该标号的提案。

批准阶段(Accept):当一个proposer收到了多数acceptors对prepare的回复后,就进入批准阶段。它要向回复prepare请求的acceptors发送accept请求,Acceptor在不违背其他提案的前提下对收到的Propose请求进行Accept处理。Proposer在收到多数节点的accept消息后,提案就已经达成。

image-20201127114330539

可以说Paxos已经很优秀了,但是还是存在问题的,每个节点都可能是Proposer,所以效率还是不够高。类比到现实生活中,如果每个人都七嘴八舌的说话,那么什么时候才可以达成一致呢。

Raft

为了解决Paxos的问题,Raft在一个任期内只允许一个节点进行提案。Raft是这么做的:

Raft算法将时间分为一个个的任期(term),每一个term的开始都是Leader选举。在成功选举Leader之后,Leader会在整个term内管理整个集群。如果Leader选举失败,该term就会因为没有Leader而结束。

image-20201127114731862

先来看Leader选举:

  1. Follower, Candidate, Leader。最开始都是Follower,正常情况下,Leader会不停的给Follower发心跳,来保持自己的权威。当Leader异常,Follower收不到新的心跳的时候,follower就变成Candidate,term加1,参加选举,当收到多数派的同意后,这个Candidate就变成了leader(如果发现leader,则降级为follower;没有获取多数派,则重新选举)。每个leader对应一个term,每个term最多只有一个leader。为了防止split vote,引入了随机化的election timeout,election timeout小的那个节点最先参与选举,有效的避免了split vote的问题。还有就是节点数尽量为奇数。
  2. 投票者的原则:一个任期只投一票;候选者的任期要比本地任期大;先到先得;

image-20201127114812874

再来看日志复制:(leader视角)

  1. 本地追加日志
  2. 并行发起rpc追加日志请求
  3. 等待节点响应(多数节点即可,不需要全部节点)
  4. 通过状态机提交数据
  5. 回复客户端
  6. 通知follower提交数据(如果某个Follower宕机,那么Leader会一直重试直到副本与与Leader状态一致)

image-20201127114856464

PBFT

上面我们提到的几种算法,本质上都属于CFT容错,即节点只可能出现宕机,不可能出现作恶的节点。在复杂的现实生活中,可能某些节点还会作恶,这就是拜占庭将军问题。这里我不在赘述,感兴趣的可以搜索。

为了解决拜占庭将军问题,其中一个典型的解决方案是PBFT。在一个拜占庭将军问题中,总节点为N的环境下,最多只能f个拜占庭节点,且N>=3f+1。

我们可以看到,这个算法的要求也蛮高的,如果有f个作恶节点,那么我们需要3f+1个正常节点,这个要求过高了。

POW

在比特币系统中,节点数量是很多的,所以PBFT算法无法使用的,在中本聪设计的比特币系统中,不再区分作恶节点,直接让利益相关方去证明一个难题。PoW算法致力于寻找一个值,使得它SHA256的hash值以若干个0开始。随着0的个数的增加,算出目标hash值的工作量耗费会呈指数上升,但是可以只通过一次hash运算就可以验证谜题。这是我当时计算的一个截图,具体的请参考:区块链的前世今生

img

总结

经过这篇文章,我相信你对我开头所提出的有了些许的感知,我也打算按照这种方式来重构我的知识体系,让我们一起互勉。

最后,我们要明白思考是手段,而不是目的。

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦