分布式系统中的一致性

分布式系统中的一致性

一致性是一个比较抽象的概念,涉及computer science的多个领域,例如:

  1. 分布式数据存储(例如分布式数据库/分布式文件系统/消息队列)的读写一致性
  2. 传统关系数据库事务隔离级别,并发事务的一致性模型
  3. 共享内存的多核架构中,多个cpu core之间的缓存一致性(cache coherence)
  4. Web cache集群的数据一致性

第三个问题是计算机体系结构专注的问题。对于软件开发者来说,只有少数的系统软件开发者(例如操作系统内核、传统关系数据库等)需要关心。第四个问题在大规模web网站中会遇到。web cache不会用来做持久化存储,开发者更多考虑的是性能问题,一致性是次要的。

与3、4不同,在前两个场景,一致性问题至关重要。一致性,简单的解释就是正确性。对于数据库/分布式存储来说,如果无法满足一定程度的正确性,没有人可以放心使用。绝对的正确性是不存在的,那么一定程度的正确性是什么呢?这就引入了consistency model问题。不同的consistency model,对于一致性的条件,有着不同的要求。consistency model可以从多个角度来划分,例如data centric,client centric。下图展示了关系数据库和分布式系统两个不同领域中常见的一致性模型:

图1. 分布式系统和数据库中的consistency model
  • 图右半部分,是关系数据库的consistency model。从上到下,一致性的级别越来越低,并发性能会更好些。不同数据库对于事务隔离级别的定义有所不同。
    • RR(repeatable read)
    • > CS(cursor scability)
    • > RC( read commit)。
  • 图左半部分,是从分布式系统的consistency model。WfR是write follows read, MR MW分别是monotonic read,monotonic write。
    • Linearizable(线性)
    • > Sequential(顺序)
    • > Causal(因果)
    • > RyW(read your write)。
  • 根据CAP理论,图中红色部分的一致性模型,无法满足100%的可用性,只能达到CP:《Highly Available Transactions: Virtues and Limitations》

对于以上几种一致性模型,做一些进一步的说明:

  1. RyW(read your write)/WfR(write follow read)都是从session sticky的角度来看一致性问题。RyW,简单的说是client写了一个key/value,那么下次读key时候应该返回的是同样的value,避免dirty read。WfR稍微有点复杂,大致上是说,如果一个写操作依赖于上一个读操作,那么在所有节点上,上一次读操作对应的写操作,一定是在本次写操作之前完成,主要是避免不同节点上写的顺序不同带来的dirty write。
  2. MR/MW:读单增(monotonic read),写单增(monotonic write )。读单增,是说client读到了一个值value,那么后续所有的读操作,要么读到这个value,要么读到这个value最新的更新,而不会读到比这个value更老的版本。写单增的定义跟读单增类似。
  3. linearizability,是在分布式系统中,是可以工程实现的、最高级别的一致性模型。

什么是linearizability呢?介绍起来还有点复杂。详细的形式化定义可以参考《Linearizability: A Correctness Condition for Concurrent Objects》。线性一致性又称为原子一致性(atomic consistency),其核心思想主要是一下几点:

  1. 从分布式系统外部(client)看,每个操作(读或者写)都是原子的,对于这些原子操作,有一个严格执行的sequence。
  2. 实际读/写操作,有latency( request timestamp-response timestamp)。对于两个读写操作X和Y来说,如果X(response timestamp)<Y(request timestamp),那么认为存在一个确定的顺序,即X<Y;否则,认为X和Y是并发的,XY之间顺序不确定的。
  3. X1,X2,X3...是某个client的读写测试结果,因为存在并发的操作,无法完全确定这些操作的sequence。但是,可以穷举出所有所有可能的Xi的顺序。如果所有的可能顺序中,其中存在一个顺序,其测试结果满足正确性的要求,那么就认为本次读写操作满足Linearizability。
图2,三操作XYZ,可能的顺序最多是3个:ZXY、XZY、XYZ。
图3 单Bit寄存器模型。A、B、C表示三个并发的process。 W(0)表示向寄存器写入0,R(1),表示从寄存器读出1。

从图3中,可以更直观的理解Linearizability的定义:

  • (a)部分满足线性,一个可能满足要求的顺序是:W(0)A -> W(1)B -> R(1)A -> W(0)C -> R(0)B。
  • (b)部分不满足线性,中间的三个操作存在并发的情况。总共有三个可能的顺序,都会推出矛盾:
    • W(0)A->W(1)B->R(1)A->W(0)C->R(1)B (最后一步矛盾)
    • W(0)A->R(1)A->W(1)B->W(0)C->R(1)B (最后一步矛盾)
    • W(0)A->R(1)A->W(0)C->W(1)B->R(1)B (第二步矛盾)

常见的分布式系统中,etcd通过raft协议,来保证读写的Linearizability。常见的nosql存储,比如redis、cassandra,都是最终一致性,并不保证强一致。elasticell在etcd的single-raft的基础上,实现了muliei-raft,是一个高性能、强一致性、动态scale的KV存储。

deepfabric/elasticellgithub.com图标


最后要卖个关子,有没有现成的工具或者框架,来验证或者测试分布式存储系统的一致性呢?且听下会分解,elasticell和jepsen测试。

参考:

Session Guarantees for Weakly Consistent Replicated Datawww.cs.cornell.edu
Strong consistency modelsaphyr.com图标Consistency modelen.wikipedia.org图标


MP HERLIHY《 Linearizability: A Correctness Condition for Concurrent Objects》

PAPADIMITRIOU, C. H. 《The serializability of concurrent database updates.》

LAMPORT, L.《How to make a multiprocessor computer that correctly executes multiprocess programs. 》

编辑于 2018-02-09

文章被以下专栏收录