A-A+

浅析分布式一致性模型

2016年12月02日 分布式 评论 3 条 阅读 7,841 次
摘要:

本文讲述分布式系统的一致性模型

一致性术语的理解

一致性这个中文术语在计算机的不同领域有不同的含义,对应的英文术语也是不一样的:Consistency, Consensus, Coherence等等。

就这三个术语而言,其区别可以简单的如下理解:

  • Coherence这个单词只在Cache Coherence场景下出现过,它关心的是多核共享内存的CPU架构下,各个核的Cache上数据如何保持一致。
  • Consensus是共识,它强调的是多个提议者就某件事情达成共识,可以说,我们关注的是达成共识的过程,例如Paxos协议,投票等。它是属于replication protocol的范畴。
  • Consistency表达的含义相比就复杂一些:
    • 广义上说,它描述了系统本身的不变量的维护程度对上层业务客户端的影响,该系统并发的状态的会暴露给客户端什么样的异常行为。CAP、ACID中的C都有这层意思。分布式系统和数据库分别独立地使用了这个术语,我认为也是基于这个术语本身的字面含义,因此将CAP的C和ACID的C视为完全无关的极端看法也是失之片面的。
    • 但是,从狭义上说,ACID与CAP又有比较明显的差别。CAP中C指的是多副本对外表现像单副本一样,从任何一个副本读取都会读到最新的值,例如Dynamo的一致性弱于GFS的一致性(Dynamo是多个副本中一部分副本写成功就对客户端返回成功,而GFS是多个副本都写成功了才对客户端返回成功)。而ACID中的C就不专门强调这个点下的含义,相反它更多表示数据库内部数据的一致性,比如参照约束等。

不过Consistency含义比较复杂,一些理解也都有争议,读者如有不同看法,欢迎留言讨论。

 

本文要说分布式系统一致性模型,是指Consistency Model。实际上,Consistency Model的问题不只是出现在分布式数据库等这类分布式系统,在多核下内存模型中也有类似的问题,或者说,这里的分布式系统是Lamport在分布式时钟事件序论文中描述的广义的分布式系统。有些一致性名字,如cache consistency,虽然是针对多核内存模型,但是同样可以对应到分布式存储系统中来。

需要说明的是,本文描述的只是比较简单的模型,即使在最近几年,都一直有学术论文就其中某些一致性展开了进一步的研究。读者如有更多相关资料,欢迎在评论中补充。如本文中描述有错误的地方,烦请读者批评指出。

 

一致性模型

参考了若干材料,基本都是从两个角度看一致性模型:data-centric consistency model和client-centric(user-centric) models。前者是从系统中数据的状态角度出发探讨一致性模型,后者是从client的角度出发探讨的。我个人觉得前者会更重要一些,适用性也更广泛一些,梳理起来难度也更大些。后者引入了session的概念,角度也有局限。本文主要着眼于前者的解释。

 

Data-Centric Consistency Models

 

1. Strict Consistency

任何读操作都能读取到最新的修改,换句话说,要求任何写操作都立刻同步到其他所有进程。这里强调的是绝对时钟上的立刻同步,而任何信息的同步都需要延迟,因此在分布式系统下无法严格实现。
不考虑系统的性能,一种可能的替代办法就是:让整个系统只在单个节点的单个线程运行。或者,在系统粒度上,读写操作操作被读写锁保护起来(另一种形式的单点运行)。
strict

可以看到,在时间轴上,一旦有进程写了x,则其他进程立刻就能读到最新的值。

 

2. Sequential Consistency

Sequential Consistency摒弃了绝对时钟的要求,而是使用分布式逻辑时钟。Sequential Consistency将所有事件定一个全序,且单个进程内的多个操作满足program order,每个进程看到的都是这个全序。

Lamport给出了一种实现方式:首先,每个进程内的读写操作按顺序issue;其次,每个进程的每个操作都被全局的一个FIFO队列定序。在这种实现方式下,同一个进程的几个操作在FIFO的顺序一定是program order,不同进程的两个操作顺序是不确定的,可能违背两个操作的绝对时间序。
sequential

如图,w1,w2,w3实际发生顺序是1<2<3,但是被定序后,可能是3<2<1。只要每个进程看到的定序结果是一致的,系统就是满足Sequential Consistency的。

 

3. Linearizability (atomic consistency) & External Consistency

Linearizability比Sequential Consistency更严格。Linearizability在Sequential Consistency的约束基础上,额外增加了如下的约束:如果操作A开始时间晚于B结束时间,则在Sequential Consistency定序时,要求B在A前。

直观上,Linearizability要求的是,操作生效时间是在操作发起到操作返回之间的某个时刻。

External Consistency这个概念好像只有数据库有(数据库可以视为多个并发事务操作共享的一组数据元素的分布式系统),它的定义方式跟Serializable是相似的。Serializable定义的一个合法的全序同时满足:各自事务内的读写操作的偏序、若干事务的偏序。External Consistency定义的一个合法全序同时满足:各自事务内的读写操作的偏序、不同事务Begin和Commit事件产生的偏序。

如果一个事务T2的开始事件晚于T1的结束时间,那么要求读取时,要么只读取到T1的结果,要么读取到T1和T2的结果,不允许出现只读取到T2的结果。在Google Spanner支持external consistency,感兴趣的读者可以参考Spanner解读了解Spanner是如何实现支持这个一致性的。

查阅了若干资料均表示,External Consistency与Linearizability是等价的,只是使用的场景不一样(注:Google在官方博客有段文字说明:Cloud Spanner provides external consistency, which is a stronger property than linearizability, because linearizability does not say anything about the behavior of transactions。我理解算是另外一种角度吧)。External Consistency名字是怎么来的?我猜测:如果一个系统的通信完全只依赖系统内部数据的读写,那么external consistency和sequential consistency是等价的。但是当系统的通信包括了外部的某些方式,即系统内部数据的关系实际还依赖系统外部定义的偏序关系,那么,二者就不再等价,external consistency就能排除sequential consistency下产生的异常现象Anomalous Behaviour。我个人认为,这个一致性可以视为带外部因果关系的sequential consistency。

Linearizability对于系统上层的业务来说,是很重要的。否则对于业务来说,就很难推断系统状态,比如我刚操作完数据d,然后把finish_flag标记为true,如果不保证linearizability,其他读者就无法依据finish_flag来安全地访问数据d。

 

4. Causal Consistency

因果关系,就是Lamport在Lamport在分布式时钟事件序论文中描述的happen-before关系及其传递闭包,即如下三种因果:

  • 同一个进程内的事件A早于B (program order)
  • A完成后发消息通知触发B
  • 已知A<B,B<C,根据传递性质推到出来的A<C

Causal Consistency要求,如果两个事件有因果关系,则要求这两个事件的先后顺序满足因果序,并且所有进程看到的这两个事件的顺序都是满足这个因果序的。

Causal Consistency相比Sequential Consistency来说,仅要求有因果关系的事件顺序对所有进程看到的一致,没有因果关系的事件顺序对于所有进程可以不一致。

casual

如图示,P2把x从1改成2,因此读取操作不允许出现R(x)2,R(x)1的现象。但是图中,y操作没有因果序,所以P3读到R(y)2,R(y)1和P4读到R(y)1,R(y)2的在Causal Consistency是允许的。这一现象,在Sequential Consistency是不允许的。不严格地说,Causal Consistency弱于Sequential Consistency。

 

5. FIFO Consistency (also known as PRAM consistency)

FIFO Consistency要求同一个进程的program order下的几个操作被其他所有进程看到的顺序是相同的。但是不同进程的几个操作被其他所有进程看到的顺序可能是不同的(即使有因果关系)。

fifo

6. Cache Consistency

FIFO Consistency要求同一个进程几个操作被其他进程看到一致的顺序。类似地, Cache Consistency要求所进程涉及到的同一个地址的几个操作,要被所有进程看到一致的顺序。FIFO Consistency和Cache Consistency相比,是两个维度的约束,这两个一致性是incomparable的。

cache

如图,P3,P4看到的x,y分别是一致的。但是x,y并不是一致的。

 

7. Processor Consistency

processor

Processor Consistency是Cache Consistency + FIFO Consistency的结合,约束更多,因此这个一致性比另外两个都更强。

 

8. Eventual Consistency

最终一致性:存储系统保证如果没有新的写操作,那么最终,所有的读操作都能读到一致的数据,这里强调对一个数据项的修改最终会收敛。

这个一致性的概念也不是特别清晰,从1975年开始,不同时间段有不同研究者在定义使用,而且近几年一直有人研究,感兴趣的读者可以参考http://www.bailis.org/这个教授的一些论文。

最终一致性在设计领域也有一些争议,可以参考这里http://queue.acm.org /detail.cfm?id=2610533。弱一致性确实带给业务一些不方便,这可能也是近几年强一致性的关系型数据库又复苏的一个原因。

 

Client-Centric(User-Centric) Models

client-centric model,也叫user-centric model。在实际应用中,从分布式系统的客户端角度,对系统的读写操作通常都依赖session这样的概念,session完全隶属于某一个进程。该模型下有如下几个一致性:Read Your Writes、Monotonic Reads、Monotonic Writes、Writs Follow Reads。

 

 

 

 

3 条留言  访客:0 条  博主:0 条

  1. konglong

    对于可线性化的一致性有这样一句描述 “如果操作A开始时间晚于B结束时间,则在Sequential Consistency定序时,要求A在B前。” 应该是 “要求B在A前” 吧。

    另外,“各自事务内的读写操作的偏序、若干事务的偏序” 这个反复出现的 “偏序” 可否详细解释哈子

    • LoopJump

      感谢指正,文中已修改。

    • LoopJump

      这个偏序就是关系代数里面说的偏序partial order。比如定义整除关系|,那么2|4,3|6,但是3\|4。
      这里说的偏序是也是这个意思。比如同一个事务内的序是前面的操作在前,后面的操作在后,但是不同事务并发的操作序是没有关系的。可以扩展一个偏序得到一个全序。

给我留言取消回复