美文网首页
区块链核心算法之一——Paxos

区块链核心算法之一——Paxos

作者: shashashashasha | 来源:发表于2018-03-16 14:21 被阅读0次

    什么是Paxos算法(一致性算法)?

    Paxos算法所解决的问题是一个分布式系统如何就某个值(决议)达成一致。一个典型的场景是,在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执行相同的操作序列,那么他们最后能得到一个一致的状态。为保证每个节点执行相同的命令序列,需要在每一条指令上执行一个“一致性算法”以保证每个节点看到的指令一致。一个通用的一致性算法可以应用在许多场景中,是分布式计算中的重要问题。 节点通信存在两种模型:共享内存和消息传递。Paxos算法就是一种基于消息传递模式的一致性算法。

    但在正式深入了解Paxos之前需要先引入三个概念:分布式系统,状态复制 和 消息传递模式。

    什么是分布式系统?

    说分布式系统必须要说集中式系统,集中式系统中整个项目就是一个独立的应用,整个应用也就是整个项目,所有的东西都在一个应用里面。

    集中式系统图示 分布式系统图示

    分布式系统就是将系统的应用层,数据层或其它部分构架成分布(物理和逻辑上的都可以)状(通常是网状)。

    比如在线游戏通常就是分布系统,里面所谓的“大区”就是分布系统里子例程。

    什么是状态复制?

    对于一组节点,如果所有节点均以相同的顺序执行一个(可能是无限的)命令序列c1,c2,c3,......,则这组节点实现了状态复制。

        · 状态复制是分布式系统的基本性质。

        · 单一节点天然实现状态复制。

    什么是消息传递模式?

    简单来说,就是在消息传递模式下构建一个分布式系统时,系统中每个节点都能进行本地运算,并可以向所有的其他节点发送消息。

    基于Paxos算法搭建分布式系统

    为了更好的深入了解Paxos算法,我们从最小的分布式系统(仅有两个节点)开始。该系统有一个客户端节点,它希望操作(储存或者更新)在远程服务器节点上的数据。

    简单发送算法

    客户端向服务器发送一条命令。

    此时服务器应该会接收到这条命令?不一定,消息传递模式下会存在“消息丢失”,在存在“消息丢失”的时候,任何一条消息都不能保证可以安全的发送给消息接收者。

    如果消息丢失,则算法无法正常工作,所以我们需要一点小小的改进。

    带确认的发送算法

    1.客户端每次向服务器发送一条命令

    2.服务器每收到一条命令,都会发送一条确认信息

    3.如果客户端没有在一个合理的时间内收到确认信息,它将重新发送命令

    每次发送一条命令指的是客户端在发送命令之后,收到确认信息之前,客户端不会发送任何新的命令。

    “带确认的发送算法”可以很容易的拓展到单客户端,多服务器的的应用场景,比如:客户端发送命令给所有的服务器,只要收到所有的服务器发回的确认消息,就可以认为此命令被执行成功。

    但是如何处理多个客户端的情况呢?

    并且在实际的应用场景里面,消息传输花费的时间是不同的(可变消息延迟模式)。多个客户端这种情况的发生尤为明显。

    序列化器实现状态复制算法

    1.所有的客户端都向序列化器发送命令,每次发送一条

    2.序列化器自动将命令排序并依次转发给所有的服务器

    3.一旦序列化器收到所有的确认信息,它将通知所有的客户端命令被成功执行

    我们通过序列化器解决了“带确认的发送算法”无法实现状态复制的问题,但是如果序列化器宕机了呢?所以,序列化器是一个很“明显”的潜在故障点!

    我们需要一个更分布式的方法:与其实现一个序列化器,不如想办法确保最多只有一个客户端在发布命令(挖矿的影子)。

    给客户端上锁算法

    阶段1

    1.客户端向所有的服务器请求锁

    阶段2

    2.if(该客户端成功获得了所有服务器的锁){

        该客户端向每个服务器发送命令,释放全部的锁

    }else{

        该客户端释法已获得的锁

        该客户端等待一段时间,再重新进入阶段1

    }

    可是“给客户端上锁算法”真的有更好的解决节点的宕机吗?不,实际上,“给客户端上锁算法”比“序列化器实现状态复制算法”更差,“序列化器实现状态复制算法”只要求一个节点必须正常工作,但是“给客户端上锁算法”却要求所有的服务器节点能够正常的响应请求。

    其实我们只得到部分服务器的响应,获得过半数以上节点的锁就足够了。所以“锁”的方式太沉重,所以我们需要一个轻量化的“锁”:

    票是一个弱化形式的锁,具备下面的性质:

        1.可重新发布:一个服务器节点可以随时发布新的票,哪怕前面发布的票还没有被释放。

        2.票可以过期:当客户端使用一张票T来发送命令时,只有当服务器验证票T为最新发布的票的时候,服务器才会接收这条命令。

    有了票之后,节点宕机的问题被解决了:一个客户端在得到一张票之后宕机了,其他客户端不会收到影响,因为服务器会发布新的票。

    且票可以用计数器来实现:没发布一张新票,计数器加一,这样每当客户端用票来请求的时候,服务器就可以判定票是否已经过期了。

    票算法

    阶段1

    1.客户端向所有的服务器请求一张票

    阶段2

    2.if(收到过半数目服务器的回复){

        客户端将获得的票和命令一期发送给每个服务器

        服务器检查票的状态,如果票仍然有效,则储存命令并给客户端发送一个反馈

    }else{

        客户端继续等待,并重新进入阶段1

    }

    阶段3

    if(客户端从过半数目服务器处得到了反馈){

        客户端告诉所有服务器执行之前储存的命令

    }else{

        客户端继续等待,并重新进入阶段1

    }

    这个算法没问题了吗?有,因为“可变消息延迟模式”,又来了。

    如果服务器不但发布票,而且还发布他当前锁储存的命令,那么U2就知道U1已经储存了命令C1,U2可不要求服务器存储命令C2,而是继续存储C1,这样两个客户端都尝试存储和执行相同的命令,那先后顺序就不重要了。

    但是如果,服务器存储的命令不一定相同,所以我们应该支持最新存储的命令。只要还不存在一个过半服务器都支持的命令,客户端们就可以随意支持任何的命令,然而一旦有一个过半数服务器一致支持的命令,那所有客户端都必须支持这个命令。

    所以,为了判定哪一个命令是最新的存储的,服务器们必须记录存储命令时客户端所用到票的编号,并且在阶段1把命令和相应的编号都告诉客户端。

    但如果每个服务器都是用自己的票号,最新的票号就不一定是一致的。

    我们需要一个全局一致的票号,因此不能让每个服务器自己维护一个自己本地的计数器来产生票号,我们可以让客户端自己来决定下一个票号T,然后去向所有的服务器请求票号为T的票,服务器收到请求之后,先将T和自己本地计数器去进行比较,只有T大于计数器的值的时候,服务器才会发布票号为T的票,并且将计数器的值更新为T。

    Paxos算法

    客户端                                                                                 服务端

    c ==> 等待执行的命令                                                         Tmax = 0  ==>  当前已发布的最大票号

    t ==> 当前尝试的票号                                                          C ==> 当前存储的命令    

                                                                                                Tc[] ==> 用来存储命令C的票

    阶段1

    1. t=t+1

    2.向所有服务器发送消息,请求编号为t的票

                                                                                                3.if(t > Tmax){

                                                                                                    Tmax = t,并回复ok(Tc[],C)

                                                                                                }

    阶段2

    4.if(过半服务器回复ok() ){

        选择Tc[]中值最大的(Tc,C)

        if(Tc > 0){

            c = C

        }

        向回复了ok的服务器发送(t,c)

    }

                                                                                                5.if(t = Tmax){

                                                                                                    C = c,Tc = t,回复success

                                                                                                }

    阶段3

    6.if(过半服务器回复success){

        向每个服务器发送消息:execute(c)

    }

    至此,一个完整的Paxos算法就成型了

    相关文章

      网友评论

          本文标题:区块链核心算法之一——Paxos

          本文链接:https://www.haomeiwen.com/subject/kfuddttx.html