分布式数据库难题(三):数据一致性

1. 什么是数据一致性

     一直以来,在“分布式系统”和“数据库”这两个学科中,一致性(Consistency)都是重要概念,但它表达的内容却并不相同。对于分布式系统而言,一致性是在探讨当系统内的一份逻辑数据存在多个物理的数据副本时,对其执行读写操作会产生什么样的结果,这也符合 CAP 理论对一致性的表述。而在数据库领域,“一致性”与事务密切相关,又进一步细化到 ACID 四个方面。其中,I 所代表的隔离性(Isolation),是“一致性”的核心内容,研究的就是如何协调事务之间的冲突。因此,当我们谈论分布式数据库的一致性时,实质上是在谈论数据一致性事务一致性两个方面。这一点,从 Google Spanner 对其外部一致性(External Consistency)的论述中也可以得到佐证。

    包括分布式数据库在内的分布式存储系统,为了避免设备与网络的不可靠带来的影响,通常会存储多个数据副本。逻辑上的一份数据同时存储在多个物理副本上,自然带来了数据一致性问题。讨论数据一致性还有一个前提,就是同时存在读操作和写操作,否则也是没有意义的。把两个因素加在一起,就是多副本数据上的一组读写策略,被称为“一致性模型”(Consistency Model)。一致性模型数量很多,让人难以分辨。为了便于你理解,我先建立一个简单的分析框架。这里,我要借用论文“The many faces of consistency”中的两个概念,状态一致性(State Consistency)和操作一致性(Operation Consistency)。不要慌,这不是新的一致性模型,它们只是观察数据一致性的两个视角。

  • 状态一致性:指的是数据所处的客观、实际状态所体现的一致性;
  • 操作一致性:指的是外部用户通过协议约定的操作,能够读取到的数据一致性。

2. 状态一致性

2.1 强一致性:MySQL 全同步复制

     现在有一个 MySQL 集群,由一主两备三个节点构成,那么在全同步复制(Fully Synchronous Replication)模式下,用户与 MySQL 交互的过程是这样的。        

    在该模式下,主库与备库同步 binlog 时,主库只有在收到两个备库的成功响应后,才能够向客户端反馈提交成功。显然,用户获得响应时,主库和备库的数据副本已经达成一致,所以后续的读操作肯定是没有问题的,但这种模式的副作用非常大,体现在以下两点。

  •  第一,性能差。主库必须等到两个备库均返回成功后,才能向用户反馈提交成功。图中由于网络阻塞,“备库 2”稍晚于“备库 1”返回响应,增加了数据库整体的延时。而下一次,拖后腿的可能变成“备库 1”。总之,主库的响应时间取决于两个备库中延时最长的那个。
  •  第二,可用性问题。我们在第 1 讲提到过可用性概念,任何设备都有可能出现故障,尤其是 x86 这样的通用商业设备,故障率会更高。但在全同步复制模式下,集群中的三个节点被串联起来,如果单机可用性是 95%,那么集群整体的可用性就是 85.7%(95%*95%*95%=85.7%),

    跟单机相比反而降低了。集群规模越大,这些问题就越严重,所以全同步复制模式在生产系统中也很少使用。更进一步说,在工程实践中,实现状态视角的强一致性需要付出的代价太大,尤其是与可用性有无法回避的冲突,所以很多产品选择了状态视角的弱一致性。

2.2 弱一致性:NoSQL 最终一致性

    NoSQL 产品是应用弱一致性的典型代表,但对弱一致性的接受仍然是有限度的,这就是 BASE 理论中的 E 所代表的最终一致性(Eventually Consistency),弱于最终一致性的产品就几乎没有了。对于最终一致性,你可以这样理解:在主副本执行写操作并反馈成功时,不要求其他副本与主副本保持一致,但在经过一段时间后这些副本最终会追上主副本的进度,重新达到数据状态的一致。

3. 操作一致性

    最终一致性,在语义上包含了很大的不确定性,所以很多时候并不是直接使用,而是加入一些限定条件,也就衍生出了若干种一致性模型。因为它们是在副本不一致的情况下,进行操作层面的封装来对外表现数据的状态,所以都可以纳入操作视角。

3.1 写后读一致性

    许多应用让用户提交一些数据,然后查看他们提交的内容。可能是用户数据库中的记录,也可能是对讨论主题的评论,或其他类似的内容。提交新数据时,必须将其发送给主库,但是当用户查看数据时,可以通过从库进行读取。如果数据经常被查看,但只是偶尔写入,这是非常合适的。但对于异步复制,问题就来了。如下图所示:如果用户在写入后马上就查看数据,则新数据可能尚未到达副本。对用户而言,看起来好像是刚提交的数据丢失了,所以他们不高兴是可以理解的。 

    这种情况下,我们需要“写后读一致性”(Read after Write Consistency),它也称为“读写一致性”,或“读自己写一致性”(Read My Writes Consistency)。你可能觉得最后一个名字听上去有些奇怪,但它却最准确地描述了这种一致性模型的使用效果。

    已写入成功的任何数据,下一刻一定能读取到,其内容保证与自己最后一次写入完全一致,这就是“读自己写一致性”名字的由来。当然,从旁观者角度看,可以称为“读你写一致性”(Read Your Writes Consistency),有些论文确实采用了这个名称。假定系统可以通过某种策略由写入节点的主副本负责后续的读取操作,这样就实现了写后读一致性,

    如何在基于领导者的复制系统中实现写后读一致性?有各种可能的技术,这里说一些:

  • 对于用户可能修改过的内容,总是从主库读取;这就要求得有办法不通过实际的查询就可以知道用户是否修改了某些东西。举个例子,社交网络上的用户个人资料信息通常只能由用户本人编辑,而不能由其他人编辑。因此一个简单的规则就是:总是从主库读取用户自己的档案,如果要读取其他用户的档案就去从库。

  • 如果应用中的大部分内容都可能被用户编辑,那这种方法就没用了,因为大部分内容都必须从主库读取(读伸缩就没效果了)。在这种情况下可以使用其他标准来决定是否从主库读取。例如可以跟踪上次更新的时间,在上次更新后的一分钟内,从主库读。还可以监控从库的复制延迟,防止向任何滞后主库超过一分钟的从库发出查询。

  • 客户端可以记住最近一次写入的时间戳,系统需要确保从库在处理该用户的读取请求时,该时间戳前的变更都已经传播到了本从库中。如果当前从库不够新,则可以从另一个从库读取,或者等待从库追赶上来。这里的时间戳可以是逻辑时间戳(表示写入顺序的东西,例如日志序列号)或实际的系统时钟(在这种情况下,时钟同步变得至关重要)。

如果你的副本分布在多个数据中心(为了在地理上接近用户或者出于可用性目的),还会有额外的复杂性。任何需要由主库提供服务的请求都必须路由到包含该主库的数据中心。

3.2 单调读一致性

    如果用户从不同从库进行多次读取,就可能发生这种情况。例如,下图显示了用户 2345 两次进行相同的查询: 

    首先查询了一个延迟很小的从库,然后是一个延迟较大的从库(如果用户刷新网页时每个请求都被路由到一个随机的服务器,这种情况就很有可能发生)。第一个查询返回了最近由用户 1234 添加的评论,但是第二个查询不返回任何东西,因为滞后的从库还没有拉取到该写入内容。实际上可以认为第二个查询是在比第一个查询更早的时间点上观察系统。如果第一个查询没有返回任何内容,那问题并不大,因为用户 2345 可能不知道用户 1234 最近添加了评论。但如果用户 2345 先看见用户 1234 的评论,然后又看到它消失,这就会让人觉得非常困惑了。

    单调读(monotonic reads)可以保证这种异常不会发生。这是一个比强一致性(strong consistency)更弱,但比最终一致性(eventual consistency)更强的保证。当读取数据时,你可能会看到一个旧值;单调读仅意味着如果一个用户顺序地进行多次读取,则他们不会看到时间回退,也就是说,如果已经读取到较新的数据,后续的读取不会得到更旧的数据。

    实现单调读一致性的方式,可以是将用户与副本建立固定的映射关系,比如使用哈希算法将用户 ID 映射到固定副本上,这样避免了在多个副本中切换,也就不会出现上面的异常了。

3.3 前缀一致性

    这天小明去看 CBA 总决赛,刚开球小明就拍了一张现场照片发到朋友圈,想要炫耀一下。小红也很喜欢篮球,但临时有事没有去现场,就在评论区问小明:“现在比分是多少?”小明回复:“4:2。”小明的同学,远在加拿大的小刚,却看到了一个奇怪的现象,评论区先出现了小明的回复“4:2。”,而后才刷到小红的评论“现在比分是多少?”。难道小明能够预知未来吗?这是什么原因呢?我们还是看图说话:

    小明和小红的评论分别写入了节点 N1 和 N2,但是它们与 N3 同步数据时,由于网络传输的问题,N3 节点接收数据的顺序与数据写入的顺序并不一致,所以小刚是先看到答案后看到问题。显然,问题与答案之间是有因果关系的,但这种关系在复制的过程中被忽略了,于是出现了异常。保持这种因果关系的一致性,被称为前缀读或前缀一致性(Consistent Prefix)。它的意思是说:如果一系列写入按某个顺序发生,那么任何人读取这些写入时,也会看见它们以同样的顺序出现。

    一种解决方案是,确保任何因果相关的写入都写入相同的分区,但在一些应用中可能无法高效地完成这种操作。还可以考虑在原有的评论数据上增加一种显式的因果关系,这样系统可以据此控制在其他进程的读取顺序。

3.4 线性一致性

    在“前缀一致性”的案例中,问题与答案之间存在一种显式声明,但在现实中,多数场景的因果关系更加复杂,也不可能要求全部做显式声明。比如对于分布式数据库来说,它无法要求应用系统在每次变更操作时附带声明一下,这次变更是因为读取了哪些数据而导致的。那么,在显式声明无法奏效的情况下,如何寻找因果关系呢?

    不知道你有没有听过这句话,“你所经历的一切,造就了现在的你。”是不是有一点哲学的味道?一切对原因的推测都是主观的,之前发生的一切都可能是原因。所以,更可靠的方式是将自然语意的因果关系转变为事件发生的先后顺序。线性一致性(Linearizability)就是建立在事件的先后顺序之上的。在线性一致性下,整个系统表现得好像只有一个副本,所有操作被记录在一条时间线上,并且被原子化,这样任意两个事件都可以比较先后顺序。这些事件一起构成的集合,在数学上称为具有“全序关系”的集合,而“全序”也称为“线性序”。我想,线性一致性大概就是因此得名。

    但是,集群中的各个节点不能做到真正的时钟同步,这样节点有各自的时间线。那么,如何将操作记录在一条时间线上呢?这就需要一个绝对时间,也就是全局时钟。从产品层面看,主流分布式数据库大多以实现线性一致性为目标,在设计之初或演进过程中纷纷引入了全局时钟,比如 Spanner、TiDB、OceanBase、GoldenDB 和巨杉等等。

    工程实现上,多数产品采用单点授时(TSO),也就是从一台时间服务器获取时间,同时配有高可靠设计; 而 Spanner 以全球化部署为目标,因为 TSO 有部署范围上的限制,所以 Spanner 的实现方式是通过 GPS 和原子钟实现的全局时钟,也就是 TrueTime,它可以保证在全球范围内任意节点能同时获得的一个绝对时间,误差在 7 毫秒以内。但是,对于线性一致性,学术界其实是有争议的。反对者的论据来自爱因斯坦的相对论的一个重要结论,“时间是相对的”。没有绝对时间,也就不存在全序的事件顺序,不同的观察者可能对于哪个事件先发生是无法达成一致的。因此,线性一致性是有局限性的。当然,从工程角度看,因为我们的应用场景都在经典物理学适用范围内,所以线性一致性也是适用的。

3.5 因果一致性

    既然线性一致性不够完美,那么有没有不依赖绝对时间的方法呢?当然是有的,这就是因果一致性(Causal Consistency)。因果一致性的基础是偏序关系,也就是说,部分事件顺序是可以比较的。至少一个节点内部的事件是可以排序的,依靠节点的本地时钟就行了;节点间如果发生通讯,则参与通讯的两个事件也是可以排序的,接收方的事件一定晚于调用方的事件。基于这种偏序关系,Leslie Lamport 在论文“Time, Clocks, and the Ordering of Events in a Distributed System”中提出了逻辑时钟的概念。借助逻辑时钟仍然可以建立全序关系,当然这个全序关系是不够精确的。因为如果两个事件并不相关,那么逻辑时钟给出的大小关系是没有意义的。

    多数观点认为,因果一致性弱于线性一致性,但在并发性能上具有优势,也足以处理多数的异常现象,所以因果一致性也在工业界得到了应用。具体到分布式数据库领域,CockroachDB 和 YugabyteDB 都在设计中采用了逻辑混合时钟(Hybrid Logical Clocks),这个方案源自 Lamport 的逻辑时钟,也取得了不错的效果。因此,这两个产品都没有实现线性一致性,而是接近于因果一致性,其中 CockroachDB 将自己的一致性模型称为“No Stale Reads”。

3.6 一致性模型强度排序

    本文介绍的几种一致性模型,用一致性强度来衡量的话:线性一致性强于因果一致性;而写后读一致性、单调读一致性、前缀一致性弱于前两者,但这三者之间无法比较强弱。综上所述,我们提到的一致性模型强度排序如下:

    线性一致性 > 因果一致性 > { 写后读一致性,单调一致性,前缀一致性 }

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在过去的十年中,对信息技术战略的普遍看法是,它是一种功能级别的战略,必须与公司选择的业务战略保持一致。 即使在这种所谓的一致性视图中,业务策略也可以指导IT策略。 在过去的十年中,业务基础架构已经变得数字化,产品,流程和服务之间的互连越来越紧密。 在跨越不同行业和部门的许多公司中,数字技术(被视为信息,计算,通信和连接技术的组合)正在从根本上改变业务策略,业务流程,公司能力,产品和服务以及扩展业务网络中关键的公司间关系。 。 因此,我们认为现在是时候重新考虑IT战略的角色了,从功能级别的战略(它始终与业务战略保持一致,但始终从属于业务战略)到反映IT战略与业务战略之间融合的战略。 这种融合在本文中被称为数字业务策略。 我们确定了四个关键主题来指导我们对数字业务战略的思考,并帮助提供一个定义下一代见解的框架。 这四个主题是(1)数字业务战略的范围,(2)数字业务战略的规模,(3)数字业务战略的速度以及(4)数字业务战略中创造和获取业务价值的来源。 在详细阐述了这四个主题之后,我们讨论了追求数字业务战略的成功指标和潜在的性能暗示。 我们还将展示本期特刊中的论文如何阐明数字策略,并提供指导以发展见识并塑造未来的研究。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值