掘金 后端 ( ) • 2024-04-30 14:30

引言

在DDIA中分布式数据系统的第五章数据复制部分讲解了部分多副本一致性和一致性模式,但是由于一致性与共识位于第九章,在初次阅读的时候不能充分理解一致性的意义,也难以区分“一致性”算法、数据库事务一致性和CAP中一致性之间的区别,这里记录一下《深入理解分布式系统》中对一致性模型的描述,用作阅读DDIA的补充。

一致性

不同语境下的一致性含义不同。其中以Paxos和Raft为代表的分布式“一致性”算法的英文实际是consensus algorithm ,因为汉语中达成一致和达成共识基本是一个意思,所以共识算法与其他几种语境下的 consistency 一致性并不表达同一个意思。

ACID中的一致性与一致性模型中的一致性是同一个英文单词,但是ACID的一致性是指数据之间的一致性,如数据库的完整性约束(主键、外键、触发器),更多的是在单机中跨表之间的约束没有被破坏。而CAP和一致性模型是用于分布式环境,用于描述多机的状态。

分布式环境下的一致性模型与复制有着密切的关系。按照冯诺依曼体系的计算模型和人类的直觉来看,读操作应该返回最近写操作所写入的结果。但是在分布式系统中,每次读写的可能是不同的主机,何时何种情况下才能保证可以读到最近的写操作的结果?一致性模型是一种开发的规则,如果遵循某个一致性模型,那么对这个分布式系统执行读操作和写操作的结果是可预测的。

image.png 图中的一致性模型根据可用性可分为三类,白色矩形代表不可用,蓝色矩形代表基本可用,紫色矩形代表高可用,具体来说:

  • 不可用(Unavailable)表示当发生网络分区时,为了保证一致性,系统会不可用
  • 基本可用(Sticky Available)表示可以容忍一部分节点故障,还未故障的节点仍然可用
  • 高可用(Total Available)表示即使发生最严重的网络分区,还未发生故障的节点依然可用。

图中的一致性强度从上到下越来越弱,即最上方的线性一致性是最强的一致性模型。

线性一致性

线性一致性(Linearizable Consistency)通俗的解释是:线性一致性的系统要像单一节点一样工作,并且所有操作是原子的。如果一个操作在时间上先于另一个操作完成,那么这个操作的效果也必须先于另一个操作对所有进程或节点可见。因此线性一致性也被称为强一致性、严格一致性、原子一致性和可线性化。

发生在系统上的所有事件可以抽象成一个并发程序的执行历史(history),假设系统只有读操作和写操作,一个操作可以分解为调用(Invocation)和响应(Response)两个事件。调用表示读操作或写操作的开始,响应表示操作结束返回状态,执行历史就是由一系列的调用和响应事件组成的。

image.png

这个图中的写操作的结果很好预测,调用前x为0,响应后x为1。扩展到一个无并发的多次读写操作,对于客户端来说,调用和响应是一个接一个的,通过按顺序检查执行每个操作后的结果是否正确即可推断执行历史的合法性。

对于并发的条件下,有多个客户端同时执行操作,每个客户端都有自己的执行历史,如果要判断某一客户端的执行历史是否合法,则要考虑到其他客户端的影响。将所有执行历史合并即可得到全局历史。

因此对于线性一致性的严格定义是,给定一个执行历史,执行历史根据并发操作可以拓展为多个顺序的全局历史,如果从中找到一个合法的顺序历史,那么该执行历史就是线性一致性的。

顺序一致性

顺序一致性(Sequential Consistency)是一种比线性一致性弱一些的一致性模型。

顺序一致性允许对并发操作历史进行重新排列,只要求同一个客户端的操作在排序后保持先后顺序不变,但不同客户端之间的先后顺序可以任意改变,即没有全局时钟的限制,只关注局部的顺序。

因果一致性

因果一致性(Causal Consistency)在顺序一致性的基础上,放宽了对同一客户端先后顺序的要求,必须以相同的顺序看到因果相关的操作,而没有因果关系的操作可以被不同的客户端以不同的顺序观察到。

最终一致性

最终一致性(Eventual Consistency)是最弱的一致性模型,只要系统最终可以达到一个稳定的状态,只要不再执行写操作,读操作将返回最新的结果,即满足最终一致性。

以客户端为中心的一致性模型

前四种一致性模型可以归类为以数据为中心的一致性模型,即以数据存储系统视角考虑多个客户端的系统状态。而另一类以客户端为中心的一致性模型则聚焦于单个客户端观察到的系统状态。

  • 单调读:客户端不会读到比前一次读的结果还旧的值
  • 单调写:同一个客户端的写操作在所有副本上以同样的顺序执行,保证客户端的写操作是串行的
  • 写后读:当写操作完成后,同一副本或其他副本上的读操作必须能够读到写入的值

PRAM一致性由上述三个一致性模型组成,同一个客户端的多个写操作将被所有的副本按照同样的执行顺序观察到,但不同客户端发出的写操作可以以不同的执行顺序观察到。

一致性与隔离级别的对比

一致性模型和隔离级别的相同点都是用来描述系统可以容忍哪些行为,不同容忍哪些行为,更严格的一致性模型和隔离级别意味着更少的异常行为,但以降低系统性能和可用性为代价。

一致性模型适用于单一对象,该对象可能存在多个副本;隔离级别通常涉及多个对象,在事务中修改数据。其中最严格的线性一致性和可串行化的区别在于是否需要实时保证,如果一个系统同时保证线性一致性和可串行化,那么则被称为严格串行化,保证多个事务执行的结果等同于串行执行结果,就像单机单线程一样。

引用

唐伟志.深入理解分布式系统