分布式数据库学习3-强一致性

如果你想真正得到一些知识,最好过滤一下你的信息,否则你只是在别人的思考中得意着。
获得多少并不取决于读了多少,而取决于思考了多少。
《暗时间》 刘未鹏

此系列学习分布式数据库30讲的笔记,导图是本文结构,具体细节在后文,可用导图回忆框架,具体细节再具体查看。

文章图片和部分内容来自极客时间,如有版权问题,请联系我删除。

欢迎加入学习

概览图

分布式数据库学习3-强一致性

分布式中一致性

分布式中的强一致性其实指的就是 事务一致性和数据一致性

事务一致性

状态一致性(State Consistency)

数据所处的客观、实际状态所体现的一致性。

也就是各个节点观察到的数据是一致的

操作一致性(Operation Consistency)

外部用户通过协议约定的操作,读取到的数据是一致的

强一致性:MySQL 全同步复制

这种情况下,只有当所有备用库同步完成后才给用户响应。主要有以下两个缺点。

  • 性能差
    多个备用库同步要花时间,且最终消耗时间取决于最晚同步完成的节点。
  • 可用性问题
    每多一个备用库节点,整体可用性变会降低。

    如果单机可用性是 95%,那么集群整体的可用性就是
    85.7%(95%*95%*95%=85.7%),跟单机相比反而降低了。

弱一致性:NoSQL 最终一致性

最终一致性

最终一致性指的是,不要求所有副本中的数据与主副本的数据一致,但经过一段时间后,其余副本的数据与主副本的数据达成一致。

但在这个一段时间内,就会有一些新的问题产生。

操作视角

写后读一致性(Read after Write Consistency)

它也称为“读写一致性”,或“读自己写一致性”(Read My Writes Consistency)

例子

以上海和杭州的存储库为例子。

a同学发了一个照片,照片先上传到了上海的存储库内,a同学立刻可以访问到这个图片。
杭州地区的副本会在后台同步这个数据,由于网络等原因,杭州地区的副本更新速度不同,但最终会达成一致。

若未完全同步之前,a同学又重新访问这个图片,若此时访问的是杭州的存储库,库内并没有这个图片,a同学会以为自己图片丢失了。

假定系统可以通过某种策略由写入节点的主副本负责后续的读取操作,这样就实现了写后读一致性,可以保证用户再次读取到照片。

单调读一致性(Monotonic Read Consistency)

数据一般是共享的,仅完成自己访问是不够的。

例子

a同学发了一个朋友圈,图片传到了上海的存储库,
b同学也看到这个朋友圈,然后刷新了,这个朋友圈消失了,b同学会误以为a同学删除了这个朋友圈。

事实上,a同学可能并没有删除,只是b同学第一次访问的是上海的节点,看到了这个朋友圈,但刷新之后访问的是杭州的节点,而杭州节点并没有完成同步。

这就出现了 b 同学误以为 a 同学删除数据的现象。

对于这种场景,系统应该实现单调读一致性(Monotonic Read Consistency)

单调读一致性(Monotonic Read Consistency)

关于单调读一致性的定义,常见的解释是这样的:一个用户一旦读到某个值,不会读到比这个值更旧的值。
变量 X 被赋值三次,依次是 10、20、30;之后读取变量 X,如果第一次读到了20,那下一次只有读到 20 或 30 才是合理的。因为在第一次读到 20 的一刻,意味着 10已经是过期数据,没有意义了

可实现方案:

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

简单来说,就是将用户第一次访问的节点保存用户信息,确保用户下一次还是访问这个节点,可以保证用户浏览到的信息不会是旧的信息。新信息总是可以同步到的,只是访问到的时间相对滞后。

前缀一致性(Consistent Prefix)

例子

但是,在一些更复杂的场景下还是会出现时间的扭曲。我再用一个例子来说明。这天小明去看 CBA 总决赛,刚开球小明就拍了一张现场照片发到朋友圈,想要炫耀一下。小红也很喜欢篮球,但临时有事没有去现场,就在评论区问小明:“现在比分是多少?”小明回复:“4:2。”小明的同学,远在加拿大的小刚,却看到了一个奇怪的现象,评论区先出现了小明的回复“4:2。”,而后才刷到小红的评论“现在比分是多少?”

实际同步流程如下:

小明和小红的评论分别写入了节点 N1 和 N2,但是它们与 N3 同步数据时,由于网络传输的问题,N3 节点接收数据的顺序与数据写入的顺序并不一致,所以小刚是先看到答案后看到问题。
显然,问题与答案之间是有因果关系的,但这种关系在复制的过程中被忽略了,于是出现了异常。

可实现方案:

前缀读或前缀一致性

保持这种因果关系的一致性,被称为前缀读或前缀一致性(Consistent Prefix)。要实现这种一致性,可以考虑在原有的评论数据上增加一种显式的因果关系,这样系统可以据此控制在其他进程的读取顺序。

线性一致性(Linearizability)

线性一致性(Linearizability)就是建立在事件的先后顺序之上的。在线性一致性下,整个系统表现得好像只有一个副本,所有操作被记录在一条时间线上,并且被原子化,这样任意两个事件都可以比较先后顺序。

为了实现这种线性关系,需要同步所有节点的时间,因此引入了一个全局时钟用来记载时间。

从产品层面看,主流分布式数据库大多以实现线性一致性为目标,在设计之初或演进过程中纷纷引入了全局时钟,比如 Spanner、TiDB、OceanBase、GoldenDB 和巨杉等等。
工程实现上,多数产品采用单点授时(TSO),也就是从一台时间服务器获取时间,同时配有高可靠设计; 而 Spanner 以全球化部署为目标,因为 TSO 有部署范围上的限制,所以 Spanner 的实现方式是通过 GPS 和原子钟实现的全局时钟,也就是 True Time,它可以保证在全球范围内任意节点能同时获得的一个绝对时间,误差在 7 毫秒内。

因果一致(CausalConsistency)

因为线性一致性不够完美,所以想再进行优化,优化到不依赖上述中提到的绝对时间。

使用因果一致性,对于节点内部而言,事件发生的顺序是可以进行排序的,对于节点之间,事件接收方的一定是晚于调用方。(先发起调用,然后才能有节点接受到)

基于这种偏序关系,Leslie Lamport 在论文“Time, Clocks, and the Ordering of Events in a Distributed System”中提出了逻辑时钟的概念。
借助逻辑时钟仍然可以建立全序关系,当然这个全序关系是不够精确的。因为如果两个事件并不相关,那么逻辑时钟给出的大小关系是没有意义的。多数观点认为,因果一致性弱于线性一致性,但在并发性能上具有优势,也足以处理多数的异常现象,所以因果一致性也在工业界得到了应用。
具体到分布式数据库领域,CockroachDB 和 YugabyteDB 都在设计中采用了逻辑混合时钟(Hybrid Logical Clocks),这个方案源自 Lamport 的逻辑时钟,也取得了不错的效果。因此,这两个产品都没有实现线性一致性,而是接近于因果一致性,其中CockroachDB 将自己的一致性模型称为“No Stale Reads”。

总结

线性一致性(需要有全局时钟) > 顺序一致性 > 因果一致性 > { 写后读一致性,单调一致性,前缀一致性 }

  • 从状态视角来看
    数据一致性可以分为强一致性和弱一致性,强一致性非常少见,最终一致性是弱一致性的特殊形式
  • 从操作视角来看
    一致性可以由多种模型来实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值