分布式一致性问题

1,448 阅读4分钟

什么是分布式一致性问题?

通常我们所说的分布式一致性问题,指的是数据一致性问题

数据一致性

数据一致性是数据库系统中的概念,数据一致性通常指关联数据之间的逻辑关系是否正确和完整。

集中式系统中,由于是一台数据库处理所有的数据请求,我们可以通过事务 + 来保证数据的ACID。

为什么会有分布式一致性问题?

我们知道分布式系统有着诸多的优点,由于系统是采用多机器分布式部署的,那么必然存在着数据的复制(如数据库的异地容灾多地部署)。分布式系统数据复制的需求来源主要有以下两个原因:

  • 消除单点故障

    将数据复制到分布式部署的多台机器中,可以消除单点故障。防止系统由于某台(些)机器宕机导致的不可用。

  • 提升系统性能

    通过负载均衡技术,能够让分布在不同地方的数据副本全都对外提供服务。有效提高系统性能。

虽说数据的复制提升了系统的性能和可用性,但是如何保证多个数据副本之间数据的一致(一致性问题)成为了一大难题。

我们几乎没有办法保证可以同时更新所有机器中的所有数据,由于网络延迟,即使我们在同一时间向所有机器发送了更新数据的请求,也无法保证所有请求的响应时间保持一致,存在时间差,就会存在某些机器的数据不一致问题。

分布式一致性模型

强一致性

要求系统写入什么,就能读取到什么;

用户体验感最佳,但很难实现,实现起来往往对系统性能影响很大

弱一致性

这种级别的一致性约束了在系统写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能的保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。

弱一致性又分为以下几种:

  • 读写一致性

    用户读取自己写入结果的一致性,保证用户永远能够第一时间看到自己更新的内容。

    比如我们发一条朋友圈,朋友圈的内容是不是第一时间被朋友看见不重要,但是一定要显示在自己的列表上。

    解决方案:

    方案1:一种方案是对于一些特定的内容我们每次都去主库读取。 (问题:主库压力大)

    方案2:我们设置一个更新时间窗口,在刚刚更新的一段时间内,我们默认都从主库读取,过了这个窗口之后,我们会挑选最近有过更新的从库进行读取

    方案3:我们直接记录用户更新的时间戳,在请求的时候把这个时间戳带上,凡是最后更新时间小于这个时间戳的从库都不予以响应。

  • 单调读一致性

    用户每次读到的数据不能比上一次的旧。

    由于主从节点更新数据的时间不一致,导致用户在不停地刷新的时候,有时候能刷出来,再次刷新之后会发现数据不见了,再刷新又可能再刷出来,就好像遇见灵异事件一样。

    解决方案:

    就是根据用户ID计算一个hash值,再通过hash值映射到机器。

    同一个用户不管怎么刷新,都只会被映射到同一台机器上。这样就保证了不会读到其他从库的内容,带来用户体验不好的影响。

  • 因果一致性

    如果节点 A 在更新完某个数据后通知了节点 B,那么节点 B 之后对该数据的访问和修改都是基于 A 更新后的值。

    与此同时,和节点 A 无因果关系的节点 C 的数据访问则没有这样的限制。

  • 最终一致性

    最终一致性是所有分布式一致性模型当中最弱的。可以认为是没有任何优化的“最”弱一致性。

    它的意思是说,我不考虑所有的中间状态的影响,只保证当没有新的更新之后,经过一段时间之后,最终系统内所有副本的数据是正确的。

    它最大程度上保证了系统的并发能力,也因此,在高并发的场景下,它也是使用最广的一致性模型。

分布式一致性的解决方案

分布式一致性问题作为分布式系统中难以忽略的难题,在长期以来的研究和探索中,也涌现了一大批的一致性协议和算法,比较有名的有大家熟知的2PC(二段式提交协议)3PC(三段式提交协议)Paxos算法等。