note4cs/技术/项目设计/分布式与系统一致性.md
2025-03-25 17:59:53 +08:00

9.1 KiB
Raw Blame History

1、分布式系统基本概念

1、CAP理论基础

分布式系统的最大难点就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。

1998年加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标:

  • Consistency 一致性
  • Availability 可用性
  • Partition tolerance 分区容错性

它们的第一个字母分别是 CAP。Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理。

它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性Consistency :等同于所有节点访问同一份最新的数据副本,或者说同一数据在不同节点上的副本在同一逻辑时钟应当是相同的内容。
  • 可用性Availability每次请求都能获取到非错的响应以及尽量保证低延迟但是不保证获取的数据为最新数据。
  • 分区容错性Partition tolerance以实际效果而言分区相当于对通信的时限要求。要求任意节点故障时,系统仍然可以对外服务。

2、数据一致性C侧

一些分布式系统通过复制数据来提高系统的可靠性和容错性,并且将数据的不同的副本存放在不同的机器,由于维护数据副本的一致性代价高,因此许多系统采用弱一致性来提高性能,一些不同的一致性模型也相继被提出。

  • 强一致性 要求无论更新操作实在哪一个副本执行,之后所有的读操作都要能获得最新的数据。
  • 弱一致性:用户读到某一操作对系统特定数据的更新需要一段时间,我们称这段时间为“不一致性窗口”。
  • 最终一致性:是弱一致性的一种特例,保证用户**最终(即窗口尽量长)**能够读取到某操作对系统特定数据的更新。

一致性解决方案

  1. 分布式事务:两段提交
  2. 分布式锁
  3. 消息队列、消息持久化、重试、幂等操作
  4. Raft / Paxos 等一致性算法

3、服务可用性A侧

可用性,意思是只要收到用户的请求,服务器就必须给出回应。

高可用解决方案

  • 负载均衡:尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性。
  • 降级:当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
  • 熔断:对于目标服务的请求和调用大量超时或失败,这时应该熔断该服务的所有调用,并且对于后续调用应直接返回,从而快速释放资源。确保在目标服务不可用的这段时间内,所有对它的调用都是立即返回的、不会阻塞的,等到目标服务好转后进行接口恢复。
  • 流量控制流量控制可以有效的防止由于网络中瞬间的大量数据对网络带来的冲击保证用户网络高效而稳定的运行类似于TCP拥塞控制方法。
  • 异地多活:在不同地区维护不同子系统,并保证子系统的可用性

熔断是减少由于下游服务故障对自己的影响;而降级则是在整个系统的角度上,考虑业务整体流量,保护核心业务稳定。

4、分区容错性P侧

大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区partition。分区容错的意思是区间通信可能失败。比如一台服务器放在中国另一台服务器放在美国这就是两个区它们之间可能无法通信。

般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 CA 无法同时做到。

2、系统一致性

1、基本要求

规范的说,理想的分布式系统一致性应该满足:

  1. 可终止性Termination一致的结果在有限时间内能完成
  2. 共识性Consensus不同节点最终完成决策的结果应该相同
  3. 合法性Validity决策的结果必须是其它进程提出的提案。

第一点很容易理解,这是计算机系统可以被使用的前提。需要注意,在现实生活中这点并不是总能得到保障的,例如取款机有时候会是 服务中断 状态,电话有时候是 无法连通 的。

第二点看似容易,但是隐藏了一些潜在信息。算法考虑的是任意的情形,凡事一旦推广到任意情形,就往往有一些惊人的结果。例如现在就剩一张票了,中关村和西单的电影院也分别刚确认过这张票的存在,然后两个电影院同时来了一个顾客要买票,从各自观察看来,自己的顾客都是第一个到的……怎么能达成结果的共识呢?记住我们的唯一秘诀:核心在于需要把两件事情进行排序,而且这个顺序还得是合理的、大家都认可的

第三点看似绕口,但是其实比较容易理解,即达成的结果必须是节点执行操作的结果。仍以卖票为例,如果两个影院各自卖出去一千张,那么达成的结果就是还剩八千张,决不能认为票售光了。

2、强一致性

线性一致性

线性一致性或称 原子一致性严格一致性 指的是程序在执行的历史中在存在可线性化点P的执行模型这意味着一个操作将在程序的调用和返回之间的某个点P起作用。这里“起作用”的意思是被系统中并发运行的所有其他线程所感知。要求如下

  1. 写后读 这里写和读是两个操作,如果写操作在完成之后,读才开始,读要能读到最新的数据,而且保证以后也能读操作也都能读到这个最新的数据。
  2. 所有操作的时序与真实物理时间一致,要求即使不相关的两个操作,如果执行有先后顺序,线性一致性要求最终执行的结果也需要满足这个先后顺序。比如,操作序列(写A读A写B读B)那么不仅读A读B能读到最新A值和B值而且要保证如果读B读到最新值时读A一定也能读到最新值也就是需要保证执行时序与真实时序相同。
  3. 如果两个操作是并发的比如读A没有结束时写B开始了那么这个并发时序不确定但从最终执行的结果来看要确保所有线程(进程,节点)看到的执行序列是一致的。

顺序一致性

相比线性一致性,主要区别在于,对于物理上有先后顺序的操作,不保证这个时序。具体而言,对于单个线程,操作的顺序仍然要保留,对于多个线程(进程,节点),执行的事件的先后顺序与物理时钟顺序不保证。但是要求,从执行结果来看,所有线程(进程,节点)看到的执行序列是一样的。

因果一致性

因果一致性,被认为是比顺序一致性更弱的一致性,在因果一致性中,只对有因果关系的事件有顺序要求。

3、带约束的一致性

绝对理想的 强一致性Strong Consistency 代价很大。除非不发生任何故障,所有节点之间的通信无需任何时间,这个时候其实就等价于一台机器了。实际上,越强的一致性要求往往意味着越弱的性能、越低的可用性。

强一致的系统往往比较难实现。很多时候,人们发现实际需求并没有那么强,可以适当放宽一致性要求,降低系统实现的难度。例如在一定约束下实现所谓 最终一致性Eventual Consistency,即总会存在一个时刻(而不是立刻),系统达到一致的状态,这对于大部分的 Web 系统来说已经足够了。这一类弱化的一致性,被笼统称为 弱一致性Weak Consistency

最终一致性

最终一致性也被称为 乐观复制(optimistic replication),用户只能读到某次更新后的值,但系统保证数据将最终达到完全一致的状态,只是所需时间不能保障。这个达成一致所需要的时间,我们称为 窗口时间

我们常见的 异步复制的主从架构实现的是最终一致性 。它的一个典型常见是用户读取异步从库时,可能读取到较旧的信息,因为该从库尚未完全与主库同步。注意,同步复制的主从架构会出现任一节点宕机导致的单点问题。

4、一致性Consistency与共识Consensus的关系

我们常说的 一致性Consistency 在分布式系统中指的是 副本Replication 问题中对于同一个数据的多个副本,其对外表现的数据一致性,如 线性一致性因果一致性最终一致性等,都是用来描述副本问题中的一致性的。

共识Consensus 则不同,共识问题中所有的节点要最终达成共识,由于最终目标是所有节点都要达成一致,所以根本 不存在一致性强弱 之分。