Zookeeper纸上谈兵——Paxos算法

3 篇文章 0 订阅
3 篇文章 0 订阅

Zookeeper纸上谈兵——Paxos算法

上回说到,这周来学习记录一下Paxos算法,之前讲了一点点的小概念,话不多说,开整。

一、算法介绍

Paxos算法是莱斯利·兰伯特(Leslie Lamport,就是 LaTeX 中的 La ,此人现在在微软研究院)于1990年提出的一种基于消息传递的一致性算法。这个算法被认为是类似算法中最有效的。(百度贴的)Google Chubby的开发者曾经说过,天下真正的一致性算法只有Paxos一个!话呢就是这么个意思,原话是就不深究了,就是说这个算法很牛,你想想,人家90年就提出来了,三十年过去了我们还在学,而且现在才是真正的得到了广大应用,大部分的一致性算法都是基于Paxos的,或者说是它的不完整实现。当然,这也是公认比较晦涩难懂,实现难度很大的算法,百度百科编辑者说可能是他在论文中论述采用故事的方式,让大家有点迷?

那么,Paxos算法的主要作用是什么呢?那就是在分布式系统中如何就某个协议或者说表决达成一致。比如,集群里面的master挂了,应该让哪一个slave来上位,担任master。

Paxos算法的前提是不存在拜占庭将军问题(想不到吧,还有个前提),所以先介绍一下拜占庭将军问题。

二、拜占庭将军问题

这个问题呢,就是当时这个Paxos算法的作者提出来的点对点通信的问题。
话说啊,拜占庭位于如今的土耳其的伊斯坦布尔,是东罗马帝国的首都。由于当时拜占庭罗马帝国国土辽阔,要守卫这么宽的领土呢,就使得每个军队都分隔很远,这些军队的首领(将军)之间只能靠通讯兵(信差)传递消息。遇到打仗的时候呢,为了谨慎起见,所有军队的将军必须要达成一致的意见,从而决定是打还是不打。但是将军们又隔得远,那时候又没有视频通信,所以每个将军呢,只能派出自己的通讯兵们将自己的意见送给其他将军。那么问题来了,万一有的通讯兵中途想妈妈了,当了逃兵或者半路撞上一打家劫舍的挂了呢?将军的意愿就无法送达;万一通讯兵中途被敌军所俘虏,敌人许以美色,通讯兵叛变了呢?那送过去的完全就是相反的了;再者,万一整个这支军队都集体叛国了,送过去的通讯兵全是间谍呢?那危险系数可就大了,没准给你整一人体炸弹,整个就要亡国呀,啊呸,那时候还没有炸药。废话好像有点多了,总之就是说这种通讯方式很不可靠,这便是拜占庭将军问题。
一般来说,分布式节点间采用的通讯模型有两种:共享内存(Shared Memory)(例子中,假如每个将军都派通讯兵到拜占庭首府进行通讯,那就是共享内存)和消息传递(Message Passing)(如故事里每个将军和其他将军单独通信,就是要派出更多的通讯兵,通信复杂度显然更高)。Paxos采用的是后者。
拜占庭将军问题要说明的就是在存在消息丢失的不可靠信道上试图通过消息传递的方式达到一致性是不可能的。
Paxos算法前提就是米有这个问题,就是说所有的信道传输是可靠的、安全的、可信赖。在实际的分布式系统中,集群都是在局域网之中,基本不会受到外网的干扰,所以这一点已经是可以实现的了。当然,互联网之间也有拜占庭将军问题,而区块链就在互联网上很好地解决了这一问题,这才有了比特币的诞生,另外,这个问题也可以延伸到很多其他的领域,感兴趣可自行百度。
那么下面就是本文的核心了。

三、算法描述

  • 三种角色
    Paxos算法中声明了三种角色,分别对应着不同的职能,当然,很多时候,有的进程是可以兼职的,即充当多个角色。

  • Proposer:提议者,负责提出提案(Proposal),下面简称P;

  • Acceptor:接受者,或者说表决者,对提议进行表决,下面简称A;

  • Learner:学习者或者说同步者,不参与表决,只同步最后的结果,下面简称L。

表决者(A)显然会存在多个,但是提议者(P)也会有多个,而且不同的提议者可以提出不同的提案。这样一来就比较复杂了,所以P还要加一些约束条件,如下:

  • P提出提案时必须为该提案指定一个集群中全局唯一的、递增的编号N;
  • 如果没有提案被提出,那就不会有提案被选定;
  • 如果一个A没有接受过提案,那么它必须接受它接收到的第一个提案;
  • 每个A在接受某提案后,会将该提案的编号N记录在本地,这样每个A中保存的已经被接受的提案中存在的一个最大编号提案,编号可定为maxN。每个表决者仅会接受编号大于自己maxN的提案。
  • 所有的提案中只能有一个被选定,一旦选定了,learner便会同步选出的提案。
  1. 算法过程
    Paxos算法分两个阶段,准备(Prepare)阶段和接受(Accept)阶段。
  • Prepare阶段
    1)P打算提出一个编号为N的提案,于是向集群中的所有A发送一个试探信息
    prepare(N),以试探表决者对这一提议的支持情况;
    2)A接收到P发出的prepare(N)之后,会将N与自己存储的maxN进行比较,如果N<maxN,那就说明这个提案已经过时,A采取不回应或者回应Error的方式表示拒绝;如果N >= maxN,那么A表示自己支持,并返回一个回应proposal(mid, maxN, value),这里的mid是A的标识id,maxN是A曾接受的提案的最大编号,value代表maxN对应提案的真正内容。那么假如当前的A还没有收到过任何提案,也就是N是它收到的第一个提案,那么它会返回proposal(mid, null, null) 以表示支持。

要注意的是Prepare阶段并不做任何的表决,表决者只是表明一个态度:我目前可以支持你的这个提案。示意图如下:
在这里插入图片描述

  • Accept阶段
    1)当P发出去prepare(N)后收到超过半数(一般集群机器数是奇数,等于半数也可以)的A发回来的proposal响应,那么A就会将自己真正的提案proposal(N, value)发给所有的表决者。
    2)当A收到proposal(N, value)提案时,会再次拿出自己曾经接受的提案编号maxN和曾经反馈的prepare请求的最大编号,将它们与N进行比较,如果N大于等于这两个值,则A接受该提案并反馈给P;否则A采取不回应或者回应Error来拒绝该提案。
    3)如果P没有收到半数及以上的A的反馈,则放弃该提案或者重新进入prepare阶段,将提案号N递增,重新发起prepare请求;如果P收到了半数及以上的A的反馈,则向外广播两类信息:
    a. 向曾 accept 其提案的表决者发送“可执行数据同步信号”,让它们执行其曾接收的提案;
    b. 此时未曾向P发送 accept 反馈的表决者将成为learner,P向它们发送“提案 + 可执行数据同步信号”,让它们接受到该提案后马上执行同步。
    这里面有几个点,首先,既然两次都是发给集群中的所有A,那为什么不在prepare阶段就直接发送提议呢?这是因为同时可能有多个提议者提出提案,而这些提案只有一个的编号最大,在表决的时候会产生很多无用的提案(所谓乌合之众),分成两个阶段可以减少这种情况。再者,为什么accept阶段要发给prepare阶段拒绝过的A呢?因为拒绝是以不回应的方式来的,所以实际上,A只确切知道哪些接受了而有的拒绝者可能是接受的,只不过接受信息丢失或者滞留了。可以看一下下面这个图,从这篇博客搬过来的,作者论文的算法介绍。
    在这里插入图片描述
    算法介绍就到这里了,感兴趣的可以百度一些例子加深下理解。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值