viewstamp replication: A new primary copy method to support highly-avaliable d

为了提升服务能力或者服务稳定,每每须要把数据重复布署,也就是replication。重复带来的问题是,更新的时候会带来不一致。一种比较简单的方法是,在N台重复的机器里选一台做为主机,其余做备份,只能经过主机更新,主机更新完全部备机后,才向上层应用返回成功。若是主机故障,则从备机中挑一台做为新的主机,这须要用到选举算法。

这里存在几个问题,一是主机崩溃前的最后一个操做进行到哪了,二是网络分隔的时候,会选出多台主机,三是有的备机曾经发生过故障,上面的数据不是最新的,不能做为主机。html

viewstampedreplication能够解决上面三个问题算法

view的含义是,能够互相联系的K台机器,以及主机ID,要求K大于集群中总机器数的一半。当有新的机器加入,或者有机器故障,或者更换主机,则变成另外一个VIEW了。数据库

必须一个VIEW中全部的机器都成功,该操做才算成功。VIEW中每台机器都记录最新一次操做的VIEWID及操做的时间戳。这样,就能够知道最后一个操做进行到哪了。由于K要求占大多数,因此不会出现多个VIEW。根据每台机器的记录,选择最新的一个,就能够知道哪些机器的数据不是最新的。网络

 

 

()Viewstamps算法并发

Viewstamps算法

1. 前言

Viewstamps算法是Oki和Liskov于1988年发表的论文,Liskov是一位计算机世界中杰出的女性,08年图灵奖得主、著名面向 对象五原则中“Liskov可替换原则”的提出者。咱们已无精力考证Viewstamps是不是第一个多数派表决的算法,但知道其比 Paxos(1998)整整早了10年,杯具的是,随着06年googlechubby论文发表,Paxos迅速闻名于世,而Viewstamps依旧寂寂无闻。分布式

2. 问题的由来

在分布式系统中通常经过复制来提升系统的可用性,而复制又引入了一致性的问题,好比咱们把数据复制到A、B、C三个节点,如何保证A、B、C看到的复制数据的顺序是一致的?从深层次上来说,复制节点就是一个状态机,咱们有必要时刻保证各状态机状态的一致。post

为了保证复制数据的一致性,Viewstamps采用了Primary-backup模式(类Master-slave),规定全部数据操做,不管是查询仍是更新都必须经过primary进行,而后传递到各backup(显然primay-backup与数据库的master-slave仍是不一样 的,数据库的master-slave强调的是“单写多读”),这样,数据的一致性就获得了保证,但primary会成为单点,若是primary crash那进行一半的事务该如何处理?这正是viewstamps算法要解决的问题,因此viewstamps也常常被描述为master的选举算法。优化

3. 概念

  • Primary Service被复制(部署)多份,每份复制称为backup,primary与众多的backup组成一个group,提供与一个primary相同的逻辑功能。
  • group里的每一个成员又被称为cohort,cohort能够是primary也能够是backup。
  • group里的所有cohor又称为configuration,group更可能是描述性的称呼,而configuration是指要在配置文件中把这个关系固定下来,是配置性的称呼。
  • configuration中超过1/2的成员又称为多数派(majority),viewstamps容许2N+1个节点中的N个节点同时失败。
  • 在某一时刻,系统的状态是有一个primary与几个backup提供服务(未必是全部的backup),这种状态称为view。
  • 在某个primary或backup crash后,这个view就会被打破,从而造成新的view,这个过程叫view change,而viewstamps又自称为view change算法。

另外补充几个次重要概念:this

  • 每一个group都有一个groupid,是配置好的,不能更改
  • 每一个view都有一个viewid,动态生成
  • 每一个cohort都有一个惟一的id
  • 每一个primary都有一个queue用来保证数据一致性,queue中的数据按照timestamp的顺序(前后顺序)保持数据
  • primary每次与backup通讯称为event
  • 每一个event一定发生在某个view中,event又是根据timestamps的顺序传递数据,所以算法叫viewstamps。
  • 事务:viewstamps 中的事务实现方式都是二段提交,即prepare和commit两个阶段。

存在众多繁杂且表述不一的概念,也是viewstamps算法的一大特点,翻来覆去就那么几样东西,你们习惯便可。google

4. 调用过程

客户端C发送数据到primary,primary传播到backups,其图以下(其中(a=primary,b,c,d,e)构成一个group,a是primary): 图1

 

很显然,在a与b,c,d,e通讯时,也称为发送event时,须要分布式事务,即等待b,c,d,e返回。若是parimary a crash,则会选举一个新的primary,以下图2

 

 

primary并非接收到event后当即同步到backup,而是在事务的prepare阶段集中处理。前面也提到过,event确定是属于某个view,event是按timestamps的顺序发送,这样全部的event就会造成一个viewstamps的顺序。好比咱们每一个view的编号 即viewid都是全序的,即每次都会单调递增,每一个event的顺序也是全序,这样每次primary接收到一个数据,均可转变为一个带全序的 event,可记录为<v1.1>,<v1.2>,<v2.1>,<v2.2>...由于一个事务能够提交多个数据最后一块儿提交,而服务端的view会随着cohort的crash而动态调整,所以客户端在与primary通讯时都 须要指定哪一个事务与primary的哪一个view通讯,而primary回复client生成的每一个event的viewstamps,以下图3:

 

 

客户端和primary都记录这些数据,以准备后续的事务提交。当客户端准备提交时,在primary接收到prepare命令时,会把其上的viewstamp记录同步到backups上,由于viewstamp全序,就保证了这些事件会以相同的顺序在backups上执行,从而获得一个一致 的状态。为了保证这一点,单靠event状态一致是不够的,还必需要求backup不能跳号执行event,好比primary要求执 行<v2.3>,但backup发现<v2.2>还没有执行,则必须等<v2.2>执行完毕后才能执 行<v2.3>。

为何会有<v2.2>还没有执行就有<v2.3>要求的状况呢?有两个缘由:一是网络波动,信息传输有时差,但这在局域网中不多发生;二是backup可能会crash后苏醒,这个状况比较常见。

Primary在向backups复制数据时并不要求全部的backups都成功,而只是要求包含本身在内的一个多数派成功便可(在viewstamps算法中,称这样的多数派为sub-majority)。这点很是重要,详细说明以下:

假如在如今时刻viewstamps系统正常运行,其全部cohort成员是confirutaion的一个多数派,记为C;

系统在屡次viewchange后仍能保持一个多数派,记为X

由于C、X都为多数派,所以C、X至少存在一个公共cohort,记为O,则cohort O知道系统在C中正常运行时的全部viewstamps,新的view能够根据O还原出viewchange前的全部工做状态,从而能为是否提交事务做出 决策。若是不能保证存在多数派,则没法保证viewstamps算法的正确性,也就是说在2N+1个节点中,最多容许N个节点失败。

5. 节点失败

cohort失败的状况比较多,但假定数据能够丢失、复制、乱序,但不能出现拜占庭问题,即不能篡改消息;另假设全部的失败都是fail-stop,即失败中止,不会在失败状态继续服务。虽然假设感受比较多,但这些假设通常的通讯环境都能知足。

节点会有下面几种失败状态:

  • 失败致使service没法访问
  • 失败后又苏醒,丢失以前的状态
  • 网络失败致使分区,好比致使cohort被分红两组,组以内的cohort能够相互访问,组之间的不能,典型的发生场景是交换机发生问题。

前两种错误会致使view change;后一种失败由于采用强制多数派的机制,保证了虽然有一个少数派的网络存在,但由于没法造成多数派而没法工做,就杜绝了存在两个viewstamps group同时工做带来的风险。

通常咱们会在cohort之间保持心跳检测,一旦某个cohort在指定的时间没有收到其余cohort的心跳则认为crash,从而发起view change。从理论上来讲,经过心跳来检测对方server是否crash是不可靠的,主要是单凭心跳时间,没法区分crash和busy,这个值的设 定跟应用所处的网络环境有很大关系。固然也可引入其余更复杂的crash检测机制,就不在这里做深刻讨论。

6. View change

如上所述,当某个cohort经过心跳发现对方已经crash时,就发起view change,可能会有多个cohort同时发起view change,因此必须保证只能创建一个新的view,基本方法以下:(假如A、B、C同时发现D失败)

   1. A构造一个新的viewid,这个view id要比A所见到的全部的view id都大,而且不一样的cohort生的view id必定不能相同,这点与paxos的proposalid很是像
   2. A发送一个invitation到其余活着的cohort,好比X
   3. X发现A发送的view id,比本身所见到的全部view id都大,因而接收邀请并回复给A;不然,X拒绝A,不作任何回应。
   4. A在接收到多数派的回应后,认为新的view已经造成,初始化新的primary;不然,没法造成新的view,一段时间后改变view id重复上述过程

在4中只是说,接收到多数派的回应,就认为新的view已经造成,要达到这个目标必须知足两个充分条件:

  • 存在一个多数派cohort接收了inviitation
  • 而且这个多数派中至少存在一个cohort知道以前全部的viewstamp

第一个条件比较容易验证,由于在Viewstamps算法中假定viewstamps的记录没有持久化,因此第二个条件不老是成立,好比:

  • 有A(primary)、B、C三个节点,A提交事务
  • event同步到B但还未到C,A crash
  • A又迅速从crash状态recovery
  • B与A、C发生了网络分区

此时的现状是:A、C能够连通,但都没有viewstamps记录,因此没法造成新view;B有viewstamps记录,但没法与A、C互通,因此也没法造成新View。所以可否造成新view须要下面三个增强条件:

  • a majority of cohorts accepted normally, or
  • crash-viewid < normal-viewid, or
  • crash-viewid = normal-viewid and the primary of view normal-viewid has done a normal acceptance of the invitation.

在造成新view后,还要继续:

    5.A寻找新的primary,并把各cohort回应的viewstamp发送给primary初始化其状态,若是老的primary没有crash,能够继续指定为primary;不然随机指定cohort做为primary
    6. 新Primary把在初始化时,把全部正确的viewstamp发送到全部的cohort,使全部的cohort状态一致。

整个过程大概如此。

7. 并发执行

在6中的过程可能有多个cohort同时执行,好比A、B同时进行view change,因此该问题本质上仍是一个选举的问题,只是对于paxos来讲,是多个proposer同时proposal选择最终决议,而如今是选择新的view。

在paxos算法中使用了2个phase解决选举的惟一性问题,而上述viewstamps的过程本质上就是paxos的phase 1,但仅凭phase1是没法达成最终决议,viewstamps 算法可能并无意识到这一点,只是认为编号高的view会被最终选择,并提出了一些避免view change并发执行的方案。由此也可看出,paxos 算法理论上比viewstamps 更完善,也有更清晰的2phase的划分。

还有一个关键问题是view在算法过程当中起了什么做用,若是没有view change而仅使用一个view是否能够?在原论文中做者提到了用view的缘由:

Over time thecommunication capability within a group may change as cohorts or communicationlinks fail and recover. To reflect this changing situation, each cohort runs ina view.

就是说,由于节点、网络都会失败、恢复,为了反映这一状况每一个节点须要运行在一个view中。

从实际应用状况来看,view反映的是节点某个时刻的运行快照,在每次新primary被选出时,须要使用正常的节点初始化其状态,但不须要全部正常节点的数据,只须要其最后一个view的viewstamps便可,若是仅采用一个view,就会每次把全部的数据都发送的新primary。

还有一种状况是网络失败,好比A、B、C三个节点,在发生网络分区,C与A、B隔离,通过一段时间网络分区修复,A、B、C又从新联通,但C上的数 据已经与A、B不一致,当再进行primary选举时就没法判断C上的数据是否可用。若是引入一个view,当C网络分区时,A、B会有新的 viewid,而分区修复时,根据viewid能明确区分出C上的数据不是最新数据。因此,引入view就是为节点引入了一个判断数据是不是最新的标志。

这也就证实了,在primary-backup模式中,当发生primary切换的时候,若是没有必定的分布式算法,仅靠backup上的数据是无 法保证新的primary能正确同步以前的状态,也就是说任何想仅经过backup去保证primary数据正确性的作法都是徒劳。

8. 优化

并非每次cohort失败都须要致使view change,若是primary没有失败,而仅backup失败,且失败后的cohort仍能构成多数派,则无需view change。但primary失败则须要view change。viewchange的过程与primary是无关的,primary的指定也是随机的,那为何primary失败缺要致使view change?其实primary切换须要2步工做:

  • 准备primary切换后的数据,为cohort造成一个新的view
  • 选择一个cohort做为primary

重要的是第一步工做,只要第一步完成了,选择哪一个cohort做为primary都不是问题。因此,表面上primary与viewchange无关,其实view change的过程就是特为primary而准备。这样是viewstamps成为选举算法的缘由。

9. 结论

Viewstams 并无从理论上完整解决选举问题,但却为leader选举及选举后的leader状态同步提出了完整的方案。

相比而言,paxos理论上更完善,2 phase的表述也更清晰,但很显然的是viewstamps不彻底等同与paxos,而只是作了paxos的phase 1。

Google chubby的人曾说,全部的分布式算法都是paxos的一个特例,信矣!

相关文章
相关标签/搜索