(接上文《架构设计:系统存储(23)——数据一致性与Paxos算法(上)》)

2-1-1. Prapare准备阶段

首先须要介绍几个在Acceptor角色上须要被持久化保存的数据属性:

  • PrepareVote保存了当前Acceptor接收到的已完毕投票授权的最大投票轮次
  • AcceptedVote保存了当前Acceptor在赋值阶段完毕投票赋值的投票轮次
  • AcceptedValue保存了当前Acceptor在赋值阶段被赋予的值

1、第一个阶段Proposer和Acceptor至少要完毕一次网络通讯,其主要目的是确定针对提议X的当前投票轮次能否被授权。换句话说,依据Acceptor在准备阶段的工作原则。即使确定当前投票轮次的编号值是大于Acceptor中记录的PrepareVote的值。处理过程非常easy,即Proposer向全部Acceptor发出关于发起提议X的新一轮投票的申请。并等待各个Acceptor进行响应。当然会有一个超时时间,假设超过这个时间还没有得到Acceptor的响应。则觉得已经被拒绝。假设有超过N/2 + 1个节点在规定的时间内没有回复响应,那就说明整个选举系统发现了问题,则终止操作抛出错误,向client反馈异常信息

2、收到这个发起新的一轮投票操作的授权请求后。各个Acceptor開始推断能否够进行授权。推断的原则仅仅与PrepareVote有关,既是假设当前申请的投票轮次小于等于PrepareVote的赋值。则拒绝授权;其他情况都要接受授权,并更改PrepareVote属性为当前新的投票伦次编号。

这里有一个隐藏含义,即这个Acceptor新授权的投票轮次编号。一定大于之前PrepareVote的值。

3、Proposer将负责汇总全部Acceptor的响应情况,并依据汇总的情况推断下一步的操作。不管Acceptor是授权这次投票还是拒绝这次投票,给出的响应信息中都最好包含当前Acceptor所记录的PrepareVote、AcceptedVote和AcceptedValue信息,这样有利于Proposer分析为什么会被Acceptor拒绝。下图展示了Proposer在汇总全部Acceptor的响应时可能出现的各种情况:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWlud2Vuamll/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

当然还有一种情况三,就是超过(包含)N/2 + 1个Acceptor节点在规定的时间内没有反馈结果,这种情况直接判定Paxos系统崩溃,所以就不做进一步讨论了。

请注意,不管是上图的哪种情况,仅仅要至少N/2 + 1个Acceptor节点的AcceptedValue为同一个值,就觉得提议X的结果达到了终于一致,整个Paxos算法过程也结束。

3.1、在Proposer得到的响应情况一中,至少N/2 + 1个Acceptor允许这轮投票。这些Acceptor就形成了一个集合Q,这个集合Q将继续下一步骤的操作。

这时集合Q中的Acceptor是否已有AcceptedValue就非常重要了:假设集合Q中没有不论什么一个Acceptor的AcceptedValue属性有值。则当前Proposer会在下一步提议自己的值为集合Q中每个Acceptor的赋值目标;假设集合Q中至少存在一个Acceptor的AcceptedValue属性有值,则Proposer会选择一个AcceptedVote最大的AcceptedValue属性值,作为当前Proposer会在下一步进行Acceptor赋值的目标。

3.2、在Proposer得到的响应情况二中,始终未达到N/2 + 1个Acceptor允许这轮投票——不管是不满足Acceptor的授权原则还是Acceptor超时未响应。仅仅要至少N/2 +1个Acceptor所回复的AcceptedValue属性值相同。则表示针对提议X已经形成了终于一致的结果,无需再进行投票了。

否则,Proposer会将自己的投票轮次编号进行添加后,再发起投票——这个添加规则兴许再讨论。读者眼下能够觉得是+1。

2-1-2. Accept赋值阶段

一旦有N/2 + 1个Acceptor节点授权了本轮投票,Proposer就能够进入第二阶段——赋值阶段。第二阶段将以上一阶段形成的多数派集合Q作为操作目标。例如以下图所看到的:

1、Proposer将会以上一阶段3.1步骤中所确定的value和自己的vote一起发送给集合Q中的每个Acceptor。并等待回复。

2、Acceptor收到赋值请求后,将会依照推断原则确认是否进行赋值。这个推断原则上文已经说过了。这里再说一次。假设当前收到的vote小于当前Acceptor的PrepareVote属性值,则不会进行赋值。为什么Acceptor上的PrepareVote会发生变化呢?这是由于在这个Proposer从第一阶段到第二阶段的操作间隙,还有一个或者多个Proposer使用编号更大的vote发起了更新一轮的投票,并得到当前Acceptor的授权。

假设当前收到的vote等于当前Acceptor的PrepareVote属性值则接受这次赋值,这时Acceptor将更改其AcceptedVote属性为vote,更改其AcceptedValue属性为value。

注意一种情况。Acceptor会不会在第二阶段操作时收到一个vote大于当前PrepareVote的赋值请求呢?这是不会的,由于不论什么Acceptor要更换PrepareVote。仅仅可能更换比当前PrepareVote更大的值。所以之前被Acceptor允许授权的vote一定会小于或者等于当前Acceptor的PrepareVote属性值。

3、赋值操作完毕后。Acceptor将向Proposer返回赋值操作后的AcceptedValue属性和AcceptedVote属性。换句话说就是,即使Acceptor拒绝了第二阶段的赋值操作,也要向Proposer返回AcceptedValue属性值。下面为Proposer端汇总统计时,可能出现的情况:

3.1、Acceptor收到集合Q中全部Acceptor的赋值结果后,就会进行汇总推断。假设发现全部赋值结果都是一样的value。则觉得针对议题X形成了终于一致的结果。整个投票过程结束,value就是达成的终于值。

3.2、假设收到集合Q中全部Acceptor的赋值结果。并进行比較的过程中。发现不论什么一个赋值结果不一致,则觉得赋值操作失败。这时Proposer会将自己的投票轮次编号进行添加后,再回到第一阶段又一次发起投票。

2-1-3. 分析一种极端情况

Paxos算法的一个核心思路在于形成多数派决议,要形成核心思路Acceptor就必须依照自己的两个工作原则进行授权操作和赋值操作。

这就是为什么我们在介绍Paxos算法时常常提到N/2 + 1的边界节点数量的原因。

由于一旦形成多数派。决定终于一致性的关键表决就能够落在唯一一个节点上,也就是说假设第X1轮投票和第X2轮投票假设都同一时候拿到了多数派Acceptor的授权,那么它们的核心战略点就是要去抢占授权X1投票的Acceptor集合和授权X2投票的Acceptor集合求交集后至少存在一个的Acceptor节点。好消息是赋值阶段X1轮投票的编号和X2轮投票的编号总是不同的。也总有大小差异的。而Acceptor的工作方式决定了它仅仅会接受编号更大的投票操作的赋值。

这个原理能够扩展到随意多个Proposer,那么有的读者会问了,会不会出现一种每个Acceptor的AcceptedValue属性都被赋值,且都没有达到多数派的特殊情况呢(例如以下图所看到的)?

答案是不会的。本小节我们将使用反向论证证的方式来进行阐述。首先要出现三个X1的赋值结果Proposer1便不能继续赋值这种现象,仅仅可能是一种情况即Proposer1在经过两阶段操作。并在进行Acceptor1~Acceptor3赋值的时候。后者三个节点上PrepareVote等于Proposer1的Vote,而在Proposer1准备进行兴许三个节点赋值时。却发现Acceptor4~Acceptor6的PrepareVote改变了。

例如以下图所看到的:

这时发起V2轮次投票的ProposerB。有两种情况。例如以下图所看到的:

第一种情况ProposerB还没有接收到至少N/2 + 1个Acceptor节点的授权结果,还处于第一阶段(这里Acceptor节点个数为6个,所以至少应该收到4个Acceptor的授权结果),这时ProposerB会一直等待汇总,假设等待超时都没有收到必要数量的结果,那么ProposerB继续添加它的投票编号。并又一次发起。这时相同能够保证Acceptor集合不被之前的Proposer继续赋值——由于投票编号仍然最大。

假设是上图所看到的的另外一种情况。就更简单了。ProposerB节点已经收到了至少4个Acceptor节点的授权结果,而这4个Acceptor节点。至少有一个节点携带了AcceptedValue为X1的值——由于眼下被赋予X1的Acceptor节点个数,刚好为一半3个节点,和N/2 + 1个节点求交集后,至少有一个重叠的Acceptor节点(注意,基数为偶数,假设为奇数就更不会出现我们如今讨论的极端情况了)。也就是说当ProposerB节点进入第二阶段赋值操作时。向剩余Acceptor节点传递的值相同为X1,而不是自身原始提议的X2,所以终于本小节最初所述的极端情况不会出现。

2-1-4、一种投票轮次的初始和添加规则

在眼下我们讨论的设计中,提到一个投票轮次的确定问题。不同Proposer发起的投票能够不一定全局递增。而同一个Proposer必须保证自己的发起的新一轮投票编号vote,一定是递增的(增量必须为1吗?这个不一定)。这是由于Acceptor在第一阶段的工作原则是,仅仅接受vote大于当前PrepareVote的新一轮投票授权,那么对于某个Proposer而言。最不济的情况就是不管自己本身怎样发起新一轮的投票,都不会得到Acceptor的授权,而终于结果仅仅能听命于别的Proposer所提议的值

非常显然上图中不管ProposerB怎样发起新一轮投票,都会在第一阶段被Acceptor拒绝掉。由于至少有一个Proposer的投票轮次编号一直比他的大。这种算法的简便处理方式尽管一定程度上降低了代码的编写难度,可是仅仅能算作伪算法实现(眼下非常多系统为了平衡性能、维护性和实现难易度。都会採用这种方式)。由于全部投票轮次的发起和赋值仅仅会听从于唯一一个Proposer。在算法的运行过程中根本就不会出现投票冲突的情况;还有一个方面,对并发状态下无法终于确认选值的Client来说也不公平,由于全部Client对终于赋值的选择也仅仅会听命于唯一一个Client(忘了说了,Client是整个Paxos中还有一个角色,这个角色负责向相应的Proposer提交须要进行表决的提案)。

所以我们须要一种投票轮次编号递增的方式,来保证不同轮次的投票请求真正的竞争起来。

有的读者可能第一个想到的就是zookeeper这种分布式协调器来生成编号,保证编号的唯一性和递增性,甚至非常多学术资料、网络文章上都有提到使用这种方式。

拜托。要是能够使用zookeeper解决问题。那我们还实现Paxos算法干什么?全部解决冲突的工作都交给zookeeper就好了嘛。之所以要实现Paxos算法,就是由于要建造一个和ZK同属一个工作层的协调组件,所以关于编号的问题就仅仅能自己想办法了。

这里介绍一种对投票轮次的编号方式,能够有效降低编号冲突,并在针提案X的投票过程中真正产生竞争。这个编号方式的前提条件是,各个Proposer工作在局域网环境下,并能通过组播的方式发现对方。在各个Proposer内部有一个使用Proposerid进行排序后的Proposer集合列表。这时就能够通过余数原则进行编号了:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWlud2Vuamll/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

(N × V) + index + 1,这个公式中。N表示集合大小。V表示投票轮次(从0開始),index表示当前Proposer所在集合的位置索引。比如,设N==4时。id为1的存在于这个有序集合列表第一个索引位置的Proposer,能够使用的投票编号就是1、5、9、13……,存在于这个有序集合列表第二个索引位置的Proposer,能够使用的投票编号就是2、6、10、14、18……,存在于这个有序集合列表第三个索引位置的Proposer,能够使用的编号就是3、7、11、15、19……

那么这种编号设计就不会反复了吗?当然会。特别是在整个Paxos算法系统的启动阶段。比如整个Paxos算法中全部N个节点的Proposer都已经启动了,可是某个Proposer上还临时仅仅发现了N-2个Proposer节点,这样该Proposer计算得出的自己所使用的编号。就可能和另外某个Proposer所计算得出的自己使用的编号反复。并且这个差异还与使用的不同节点发现方式而不同。比如在兴许文章中给出的Basic-Paxos算法实现代码中。就使用组播方式进行Proposer节点发现,而这种节点发现方式就会使每个Proposer节点上的节点发现进度在Paxos算法系统启动之初出现不一致。

只是好消息是,Acceptor在第一阶段的工作原则中,仅仅会授权大于当前AcceptedVote的投票申请(此时AcceptedVote <= PrepareVote)。也就是说当两个或者多个持有相同投票伦次的Proposer向同一个Acceptor申请投票授权时。Acceptor仅仅会授权当中一个。还有一个的授权申请将被Acceptor拒绝。这就保证了有相同投票轮次编号的授权请求在同一个Acceptor上不会被反复允许,那么这些有相同投票轮次编号的Proposer就能够决定自己是否拿到了授权多数派。假设没有拿到授权,当Proposer集合稳定存在后。就会有新的且更大的投票轮次编号了。

===============

(接下文)

架构设计:系统存储(24)——数据一致性与Paxos算法(中)的更多相关文章

  1. zookeeper数据一致性与paxos算法

    数据一致性与paxos算法 据说Paxos算法的难理解与算法的知名度一样令人敬仰,所以我们先看如何保持数据的一致性,这里有个原则就是: 在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点都执 ...

  2. ios app架构设计系统文章

    三. iOS应用架构谈(三):网络层设计方案(上) http://www.infoq.com/cn/articles/ios-app-arch-3-1?utm_source=infoq&utm ...

  3. [业务监控系统]MEDIVH架构设计和接入方案

    Medivh监控系统- 系统介绍 本系统旨在提供业务监控实时数据和历史数据以及报表.阈值报警.同比增长分析等一体化的历史业务数据解决方案. 技术选型 sdk部门有C#版和java版,api和websi ...

  4. [开发笔记usbTOcan]系统架构设计

    SYS.3 | 系统架构设计 系统架构设计过程的目的是建立一个系统体系结构设计,并确定哪些系统需求分配给系统的哪些元素,并根据确定的标准评估系统架构. 系统结构设计需要做一下工作: 开发系统架构设计. ...

  5. 浅谈 jQuery 核心架构设计

    jQuery对于大家而言并不陌生,因此关于它是什么以及它的作用,在这里我就不多言了,而本篇文章的目的是想通过对源码简单的分析来讨论 jQuery 的核心架构设计,以及jQuery 是如何利用javas ...

  6. 谈一谈jQuery核心架构设计(转)

    jQuery对于大家而言并不陌生,因此关于它是什么以及它的作用,在这里我就不多言了,而本篇文章的目的是想通过对源码简单的分析来讨论 jQuery 的核心架构设计,以及jQuery 是如何利用javas ...

  7. 浅析 jQuery 内部架构设计

    jQuery 对于大家而言并不陌生,因此关于它是什么以及它的作用,在这里我就不多言了,而本篇文章的目的是想通过对源码简单的分析来讨论 jQuery 的内部架构设计,以及 jQuery 是如何利用Jav ...

  8. Android App的架构设计:从VM、MVC、MVP到MVVM

    随着Android应用开发规模的扩大,客户端业务逻辑也越来越复杂,已然不是简单的数据展示了.如同后端开发遇到瓶颈时采用的组件拆分思想,客户端也需要进行架构设计,拆分视图和数据,解除模块之间的耦合,提高 ...

  9. Java生鲜电商平台-订单模块状态机架构设计

    Java生鲜电商平台-订单模块状态机架构设计 说明:在Java生鲜电商平台中订单的状态流转业务        我们知道 一个订单会有很多种状态:临时单.已下单.待支付.待收货.待评价.已完成,退货中等 ...

随机推荐

  1. linux下的文件结构

    linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令/dev 设备特殊文件/etc 系统管理和配置文件/etc/rc.d 启动的配置文件和脚本/home 用户主目录的基点,比如 ...

  2. poj2299树状数组入门,求逆序对

    今天入门了树状数组 习题链接 https://blog.csdn.net/liuqiyao_01/article/details/26963913 离散化数据:用一个数组来记录每个值在数列中的排名,不 ...

  3. 通配符(WildCard)的使用

    一.关于WildCard:一个web应用,有成千上万个action声明,可以利用struts2提供的映射机制把多个彼此相似的映射关系简化成一个映射关系,即通配符. 1.新建类 ActionWildCa ...

  4. whiledo循环输出9-0

    var i=9 while(i>-1){ println(i); i--; } function println(a) { document.write(a+"<br>&q ...

  5. HTML5布局

    完整示例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  6. Android Rom build.prop文件详解

    # begin build properties   # autogenerated by buildinfo.sh   #以下内容由脚本在编译时自动产生 ro.build.id=6.7.7_97  ...

  7. Highcharts实现图形报表(我主要实现javaweb开发的图形报表)

    官网网址:https://www.hcharts.cn/ 中文版的(参考起来方便,你懂的.):http://www.mamicode.com/info-detail-446038.html 网上已经有 ...

  8. day10--进程

        进程: Python 解释器有一个全局解释器锁(PIL),导致每个 Python 进程中最多同时运行一个线程,因此 Python 多线程程序并不能改善程序性能,不能发挥多核系统的优势,可以通过 ...

  9. STM32的HAL库中的DMA_FLAG_TCIF3_7等几个宏定义的含义

    DMA_FLAG_TCIF0_4就是指DMA的通道0和通道4,DMA_FLAG_TCIF1_5就是指DMA的通道1和通道5,DMA_FLAG_TCIF2_6就是指DMA的通道2和通道6,DMA_FLA ...

  10. python全栈开发day39-CSS继承性和层叠性、权重问题、盒模型和其属性、文本级标签和块级标签、浮动

    一.上次内容回顾 1.CSS的三种引入方式: 行内式 内接式 外接式 链接式 导入式 2.基础选择器和高级选择器 1)标签选择器 p{} 2)  id选择器 #nva{} 3) 类选择器 .nva{} ...