分布式系统 一致性和共识

文章目录

    • 一致性和共识的区别
    • 一致性
      • 严格一致性
      • 顺序一致性
      • 强一致性(线性一致性)
      • 顺序一致性和线性一致性的区别
      • 弱一致性
      • 最终一致性
    • 共识
    • 总结

一致性和共识的区别

一致性往往指分布式系统中多个副本对外呈现的数据的状态。共识则描述了分布式系统中多个节点之间,彼此对某个状态达成一致结果的过程。因此,一致性描述的是结果状态,共识则是一种手段。

在分布式系统中,我们常说的一致性问题就是:对于同一个数据的多个副本之间,如何保持其对外表现的数据一致性。例如,研究客户端B怎样能读取到客户端A做的修改,然后两者之间的数据可以达成一致。

在实践中,要保障系统满足不同程度的一致性,核心过程往往需要通过共识算法来达成。共识算法解决的是对某个提案大家达成一致意见的过程。

一致性

分布式系统中的一致性按照对一致性要求的不同,主要分为,严格一致性,强一致性(线性一致性),顺序一致性,弱一致性、最终一致性。

严格一致性

假如有人说他设计了一个满足严格一致性的分布式系统,那么这个系统的外部表现就应该完全等价于一台计算机。这意味着,对于这个系统中任意数据项x的任何读操作将返回最近一次对x进行的写操作的结果所对应的值。对于所有的进程来说,所有写操作都是瞬间可见的,系统维持着一个绝对的全局时间顺序。

事实上,严格一致性要求系统不发生任何故障,而且所有节点之间的通信无需任何时间这种理想的条件下,才能达到。因此现实世界中,这样的分布式系统是不存在的。
分布式系统 一致性和共识_第1张图片

顺序一致性

在讲强一致性之前,首先要讲一下顺序一致性,它虽然不满足强一致性,但是又优于弱一致性,是一种过渡状态。

Leslie Lamport 在1979年提出了顺序一致性,对系统提出了两条访问共享对象时的约束:

  • 从单个处理器(线程或者进程)的角度上看,其指令的执行顺序以编程中的顺序为准;
  • 从所有处理器(线程或者进程)的角度上看,指令的执行保持一个单一的顺序;

更通俗的解释,顺序一致性要满足两个条件:

  • 每个进程的内部操作顺序是确定不变的
  • 假设所有的进程都对一个存储单元执行操作,那么任一进程都可以感知到相同的操作顺序,即使感知到的操作顺序与实际的全局时钟顺序不同。(实际上就是保证所有进程感知到的写操作顺序是相同的)

顺序一致性的关键在于找到一个满足现实情况的全局执行顺序,使其同时又能符合每个单独进程内部的操作顺序。
分布式系统 一致性和共识_第2张图片
以上图片中(a)为顺序一致性,(b)不为顺序一致性。
对于(a),由于要保持进程内部的操作顺序不能变,所以P3和P4中都是先读取x=b再读到x=a,所有两者感知到的写顺序是相同的,感知到的整体操作顺序为W(x)b -> R(x)b -> W(x)a -> R(x)a。
对于(b),P3和P4感知到的写操作顺序不同,导致无法找到一个符合顺序一致性的整体操作顺序。

顺序一致性中没有全局时钟的限制,多个进程的操作可以任意调整顺序,以找到符合每个单独进程内部的操作顺序的全局操作顺序。所以如果每个进程中感知到的写操作顺序是相同的,那么一定可以通过调整读操作的顺序来获得符合要求的全局操作顺序,那么一定是顺序一致性的。

强一致性(线性一致性)

当一个数据副本的更新操作完成之后,任何多个后续节点对这个数据的任意副本的访问都会返回最新的更新过的值。强一致性和严格一致性的区别在于强一致性中写操作是耗时的,对系统可用性的影响较大,只要上次的操作没有处理完,就不能让用户读取数据。

线性一致性,是一种强一致性,在顺序一致性前提下加强了进程间的操作排序,形成唯一的全局顺序。线性一致性假设操作具有一个全局有效时钟的时间戳,要求时间戳在前的进程先执行,从而确定唯一的全局操作顺序,即所有的操作按照全局时钟的顺序被所有进程感知。

顺序一致性和线性一致性的区别

两者都要求所有进程感知到整体操作顺序是相同的。所有的写操作都以相同的顺序被每个进程感知。

但是在顺序一致性中只需要保证单个进程中的操作顺序确定不变,而没有全局时钟的限制,多个进程中的操作可以任意排序,所以进程感知到的整体操作顺序可以不符合实际的全局时钟。只要能保证所有进程感知到相同的写操作顺序,即可保证顺序一致性。
在线性一致性中,在顺序一致性的基础上,有了全局时钟的限制,所有操作必须按照全局时钟顺序,确定了唯一的全局顺序。同时这也保证了写操作之后,读操作必须读取最新数据,即强一致性。
顺序一致性中,读操作可以不用读取最新的数据,即非强一致性。线性一致性中,读操作必须读取最新的数据,即强一致性。

分布式系统 一致性和共识_第3张图片
图(a)满足顺序一致性,但是不满足线性一致性的。原因在于,从全局时钟的观点来看,P2进程对变量X的读操作在P1进程对变量X的写操作之后,然而读出来的却是脏数据。但是确实符合顺序一致性的,因为P1和P2感知到相同的写操作顺序: Write(y,2) ,Write(x,4)(虽然这并未从图上显示出来)。所以P1和P2可以感知到相同的整体操作顺序:Write(y,2) , Read(x,0) , Write(x,4), Read(y,2)。每个进程内部的读写顺序都是合理的,但是这个顺序与全局时钟下看到的顺序并不一样。

图(b)满足强一致性,因为每个读操作都读到了该变量的最新写的结果,同时两个进程看到的操作顺序与全局时钟的顺序一样,都是Write(y,2) , Write(x,4), Read(x,4) ,Read(y,2)。

一句话总结:顺序一致性要求所有进程感知到相同的操作顺序(本质上只需要保证感知到相同的写操作顺序),只要求单进程中操作顺序不变,整体顺序可以不遵循全局时钟。线性一致性要求所有进程感知到相同的按照全局时钟确定的整体操作顺序。

弱一致性

弱一致性是指系统并不保证后续进程或线程的访问都会返回最新的更新的值。系统在数据成功吸入之后,不承诺立即可以读到最新写入的值,也不会具体承诺多久读到。但是会尽可能保证在某个时间级别(秒级)之后。可以让数据达到一致性状态。

最终一致性

最终一致性是弱一致性的一种特例。某个进程更新了副本的数据,如果没有其他进程更新这个副本的数据,系统最终一定能够保证后续进程能够读取到写进的最新值。

最终一致性根据更新数据后各进程访问到数据的时间和方式的不同,又可以区分为:

  • 因果一致性。如果进程A通知进程B它已更新了一个数据项,那么进程B的后续访问将返回更新后的值,且一次写入将保证取代前一次写入。与进程A无因果关系的进程C的访问遵守一般的最终一致性规则。
  • “读己之所写(read-your-writes)”一致性。当进程A自己更新一个数据项之后,它总是访问到更新过的值,绝不会看到旧值。这是因果一致性模型的一个特例。
  • 会话(Session)一致性。保证在同一个会话中,实现“读己之所写”一致性。如果由于某些失败情形令会话终止,就要建立新的会话,而且系统的保证不会延续到新的会话。
  • 单调(Monotonic)读一致性。如果进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值之前的值。
  • 单调写一致性。系统保证来自同一个进程的写操作顺序执行。要是系统不能保证这种程度的一致性,就非常难以编程了。

共识

分布式系统 一致性和共识_第4张图片
为了达到共识,每个进程都提出自己的提议(propose),最终通过共识算法,所有正确运行的进程决定(decide)相同的值。

根据解决的是非拜占庭的普通共识问题还是拜占庭共识问题(是否允许系统内节点作恶,以及对完备性的不同要求),共识算法可以分为Crash Fault Tolerance(CFT)类算法和Byzantine Fault Tolerance(BFT)类算法。

针对常见的非拜占庭错误的情况,已经存在一些经典的解决算法,包括Paxos、Raft及其变种等。这类容错算法往往性能比较好,处理较快,容忍不超过一半的故障节点。对于要能容忍拜占庭错误的情况,一般包括PBFT(Practical Byzantine Fault Tolerance)为代表的确定性系列算法、PoW为代表的概率算法等。

对于确定性算法,一旦达成对某个结果的共识就不可逆转,即共识是最终结果;而对于概率类算法,共识结果则是临时的,随着时间推移或某种强化,共识结果被推翻的概率越来越小,成为事实上的最终结果。拜占庭类容错算法往往性能较差,容忍不超过1/3的故障节点。

总结

一致性往往指分布式系统中多个副本对外呈现的数据的状态。如前面提到的顺序一致性、线性一致性,描述了多个节点对数据状态的维护能力。
共识则描述了分布式系统中多个节点之间,彼此对某个提案达成一致结果的过程。因此,一致性描述的是结果,共识则是一种手段。
共识方法可以用来实现强一致性。

参考博客:
https://zhuanlan.zhihu.com/p/68743917
https://www.cnblogs.com/xdyixia/p/11716079.html
https://wenku.baidu.com/view/2038aff77c1cfad6195fa7d4.html
https://blog.csdn.net/chao2016/article/details/81149674
https://blog.csdn.net/cadem/article/details/80359270

你可能感兴趣的:(分布式系统)