博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分布式-CAP
阅读量:2181 次
发布时间:2019-05-01

本文共 5614 字,大约阅读时间需要 18 分钟。

分布式-CAP

转载声明

本文大量内容系转载自以下文章,有删改,并参考其他文档资料加入了一些内容:

  • 作者:58沈剑
    出处:架构师之路

  • 作者:陈彩华
    出处:51CTO技术栈

摘要

分布式系统非常关注三个指标:

  • C
    数据一致性
  • A
    系统可用性
  • P
    节点连通性与扩展性

0x01 C-一致性

A read is guaranteed to return the most recent write for a given client.

数据“强一致性”,是希望系统只读到最新写入的数据,例如:通过单点串行化的方式,就能够达到这个效果。

注意,这里并不是强调同一时刻拥有相同的数据,对于系统执行事务来说,在事务执行过程中,系统其实处于一个不一致的状态,不同的节点的数据并不完全一致。一致性强调客户端读操作能够获取最新的写操作结果,是因为事务在执行过程中,客户端是无法读取到未提交的数据的。只有等到事务提交后,客户端才能读取到事务写入的数据,而如果事务失败则会进行回滚,客户端也不会读取到事务中间写入的数据。

关于session一致性,DB主从一致性,DB双主一致性,DB与Cache一致性,数据冗余一致性,消息时序一致性,分布式事务一致性,库存扣减一致性,详见文章《究竟啥才是互联网架构“一致性”》。

0x02 A-可用性

A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout).

非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。这里强调的是合理的响应,不能超时,不能出错。注意并没有说“正确”的结果,例如,应该返回 100 但实际上返回了 90,肯定是不正确的结果,但可以是一个合理的结果。

如果系统每运行100个时间单位,会有1个时间单位无法提供服务,则说系统的可用性是99%。

可用性和可靠性是比较容易搞混的两个指标,以一台取款机为例:

  • 正确的输入,能够取到正确的钱,表示系统可靠
  • 取款机7*24小时提供服务,表示系统可用

保证系统高可用的方法是:

  • 冗余
  • FailOver(故障自动转移)

反向代理层,站点层,服务层,缓存层,数据库层各层保证系统高可用的方法,详见文章。

0x03 P-连通性与扩展性

The system will continue to function when network partitions occur.

当出现网络分区后,系统能够继续“履行职责”。

这里网络分区是指:一个分布式系统里面,节点组成的网络本来应该是连通的。

然而可能因为一些故障(节点间网络连接断开、节点宕机),使得有些节点之间不连通了,整个网络就分成了几块区域,数据就散布在了这些不连通的区域中。

分布式系统,往往有多个节点,每个节点之间,都不是完全独立的,需要相互通信,当发生节点无法联通时,数据是否还能保持一致,系统要如何进行容错处理,是需要考虑的。

同时,连通性和扩展性紧密相关,想要加机器扩展性能,必须有良好的连通性。当一个节点脱离系统,系统就出现问题,往往意味着系统是无法扩展的。

反向代理层,站点层,服务层,缓存层,数据库层各层保证系统扩展性的方法,详见文章。

0x04 什么是CAP定理?

CAP

4.1 简介

CAP定理,是对上述分布式系统的三个特性,进行了归纳:

  • 一致性(Consistency)
  • 可用性(Availability)
  • 分区容忍性(Partition Tolerance)
    并且,定理指出,在系统实现时,这三者最多兼顾两点。

4.2 互联网最常见的实践

4.2.1 P-分区容忍最重要

  • 节点连通性,多节点扩展性,连通性异常的处理必须保证,满足P。因为在分布式环境下来思考,我们会发现必须选择 P(分区容忍)要素,因为网络本身无法做到 100% 可靠,有可能出故障,所以分区是一个必然的现象。

4.2.2 一致性C与可用性A一般二选一,再加P

如果我们选择了 CA(一致性 + 可用性) 而放弃了 P(分区容忍性),那么当发生分区现象时,为了保证 C(一致性),系统需要禁止写入。

当有写入请求时,系统返回 error(例如,当前系统不允许写入),这又和 A(可用性) 冲突了,因为 A(可用性)要求返回 no error 和 no timeout。

因此,分布式系统理论上不可能选择 CA (一致性 + 可用性)架构,只能选择 CP(一致性 + 分区容忍性) 或者 AP (可用性 + 分区容忍性)架构,在一致性和可用性做折中选择。

4.2.3 CP

举例:传统单库水平切分,就是这类选型的典型。HBase也是CP。

CP
如上图所示,因为 Node1 节点和 Node2 节点连接中断导致分区现象,Node1 节点的数据已经更新到 y,但是 Node1 和 Node2 之间的复制通道中断,数据 y 无法同步到 Node2,Node2 节点上的数据还是旧数据 x。

这时客户端 C 访问 Node2 时,Node2 需要返回 error,提示客户端 “系统现在发生了错误”,这种处理方式违背了可用性(Availability)的要求,因此 CAP 三者只能满足 CP。

4.2.4 AP

举例:双主库同步高可用,就是这类选型的典型

AP
同样是 Node2 节点上的数据还是旧数据 x,这时客户端 C 访问 Node2 时,Node2 将当前自己拥有的数据 x 返回给客户端了。

而实际上当前最新的数据已经是 y 了,这就不满足一致性(Consistency)的要求了,因此 CAP 三者只能满足 AP。

注意:这里 Node2 节点返回 x,虽然不是一个“正确”的结果,但是一个“合理”的结果,因为 x 是旧的数据,并不是一个错乱的值,只是不是最新的数据。

另外,只能选择 CP 或者 AP 是指系统发生分区现象时无法同时保证 C(一致性)和 A(可用性),但不是意味着什么都不做,当分区故障解决后,系统还是要保持保证 CA(比如最终以一致性)。

4.3 强一致很难怎么办?

单点串行化,虽然能保证“强一致”,但对系统的并发性能,以及高可用有较大影响,互联网的玩法,更多的是“最终一致性”,即短期内未必读到最新的数据,但在一个可接受的时间窗口之后,能够读到最新的数据。

例如:数据库主从同步,从库上的数据,就是一个最终的一致。

0x05 BASE-CAP的延伸

5.1 简介

BASE

BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency)。

它的核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。

5.2 BA-Basically Available 基本可用

分布式系统在出现故障时,允许损失部分功能可用性,即保证核心可用。

这里的关键词是“部分”和“核心”,实践中,哪些是核心需要根据具体业务来权衡。

例如登录功能相对注册功能更加核心,注册不了最多影响流失一部分用户,如果用户已经注册但无法登录,那就意味着用户无法使用系统,造成的影响范围更大。

5.3 S-Soft State 软状态

允许系统存在中间状态,而该中间状态不会影响系统整体可用性。这里的中间状态就是 CAP 理论中的数据不一致。

5.4 E - Eventual Consistency 最终一致性

系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。

这里的关键词是“一定时间” 和 “最终”,“一定时间”和数据的特性是强关联的,不同业务不同数据能够容忍的不一致时间是不同的。

例如支付类业务是要求秒级别内达到一致,因为用户时时关注;用户发的最新微博,可以容忍 30 分钟内达到一致的状态,因为用户短时间看不到明星发的微博是无感知的。

而“最终”的含义就是不管多长时间,最终还是要达到一致性的状态。

5.5 BASE理论本质

BASE 理论本质上是对 CAP 的延伸和补充,更具体地说,是对 CAP 中 AP 方案的一个补充: CAP 理论是忽略延时的,而实际应用中延时是无法避免的。

这一点就意味着完美的 CP 场景是不存在的,即使是几毫秒的数据复制延迟,在这几毫秒时间间隔内,系统是不符合 CP 要求的。

因此 CAP 中的 CP 方案,实际上也是实现了最终一致性,只是“一定时间”是指几毫秒而已。

AP 方案中牺牲一致性只是指发生分区故障期间,而不是永远放弃一致性。这一点其实就是 BASE 理论延伸的地方,分区期间牺牲一致性,但分区故障恢复后,系统应该达到最终一致性。

0x06 数据一致性模型

6.1 概述

前面介绍的 BASE 模型提过“强一致性”和“最终一致性”,下面对这些一致性模型展开介绍。

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

下面介绍常见的一致性模型:

6.2 强一致性

要求无论更新操作是在哪个数据副本上执行,之后所有的读操作都要能获得最新的数据。

对于单副本数据来说,读写操作是在同一数据上执行的,容易保证强一致性。

对多副本数据来说,则需要使用分布式事务协议。或者,写入的时候,必须所有副本节点都反馈接收成功,该条消息才对消费者可见。

例子:

  • Kafka

    配置为all时,必须isr副本都应答,leader才提升水位,小于水位的offset才对consumer可见。而且Consumer只会从leader读取数据。

  • HBase

    HBase每一Rowkey只会在一个Region,Region只会存在于一个RegionSever上。如果这个RS挂了,则会利用底层Store File或WAL Log(都存在HDFS)来恢复数据,此时数据可能会短暂地查不到,不可用。所以HBase属于CP的。

    如果数据还没有写入HDFS,那么会先在Memstore,此时也只会在一个RS上。

    更多详情,可参考

6.3 弱一致性

在这种一致性下,用户读到某一操作对系统特定数据的更新需要一段时间,我们将这段时间称为"不一致性窗口"。

"不一致性窗口"的大小依赖于交互延迟、系统的负载,以及数据的副本数等。

6.4 最终一致性

是弱一致性的一种特例,在这种一致性下系统保证用户最终能够读取到某操作对系统特定数据的更新(读取操作之前没有该数据的其他更新操作)。

系统选择哪种一致性模型取决于应用对一致性的需求,所选取的一致性模型还会影响到系统如何处理用户的请求以及对副本维护技术的选择等。

例子

  • Elasticsearch

    对于读请求,为了平衡负载,请求节点会为每个请求选择不同的分片——它会循环所有分片副本(主分片和副本分片)。

    可能的情况是,一个被索引的文档已经存在于主分片上却还没来得及同步到复制分片上。这时复制分片会报告文档未找到,而主分片会成功返回文档。一旦索引请求成功返回给用户,文档则在主分片和复制分片都是可用的。

6.5 顺序一致性

可参考

来自某个客户端的多个更新,会按发送顺序被提交。即某个客户端先将znode z修改为a,然后又修改为b,则其他客户端无法在看到节点z 为b后又变回为a。

ZK的顺序一致性是由Zab协议依赖TCP(zxid小的更新事务一定发生在zxid大的之前)来保证的,而不是paxos算法。

0x07 柔性事务

7.1 柔性事务的概念

在电商等互联网场景下,传统的事务在数据库性能和处理能力上都暴露出了瓶颈。在分布式领域基于 CAP 理论以及 BASE 理论,有人就提出了柔性事务的概念。

基于 BASE 理论的设计思想,柔性事务下,在不影响系统整体可用性的情况下(Basically Available 基本可用),允许系统存在数据不一致的中间状态(Soft State 软状态),在经过数据同步的延时之后,最终数据能够达到一致。

并不是完全放弃了 ACID,而是通过放宽一致性要求,借助本地事务来实现最终分布式事务一致性的同时也保证系统的吞吐。

7.2 实现柔性事务的一些特性

下面介绍的是实现柔性事务的一些常见特性,这些特性在具体的方案中不一定都要满足,因为不同的方案要求不一样。

7.2.1 可见性(对外可查询)

在分布式事务执行过程中,如果某一个步骤执行出错,就需要明确的知道其他几个操作的处理情况,这就需要其他的服务都能够提供查询接口,保证可以通过查询来判断操作的处理情况。

为了保证操作的可查询,需要对于每一个服务的每一次调用都有一个全局唯一的标识,可以是业务单据号(如订单号)、也可以是系统分配的操作流水号(如支付记录流水号)。除此之外,操作的时间信息也要有完整的记录。

7.2.2 操作幂等性

幂等性,其实是一个数学概念。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。

幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。也就是说,同一个方法,使用同样的参数,调用多次产生的业务结果与调用一次产生的业务结果相同。

之所以需要操作幂等性,是因为为了保证数据的最终一致性,很多事务协议都会有很多重试的操作,如果一个方法不保证幂等,那么将无法被重试。

幂等操作的实现方式有多种,如在系统中缓存所有的请求与处理结果、检测到重复操作后,直接返回上一次的处理结果等。

0xFE 总结

  • CAP可以理解为一致性,可用性,联通与扩展性
  • CAP三者只能取其二
  • 最常见的实践是AP+最终一致性
你可能感兴趣的文章
Java集合详解8:Java集合类细节精讲,细节决定成败
查看>>
Java并发指南1:并发基础与Java多线程
查看>>
Java并发指南2:深入理解Java内存模型JMM
查看>>
Java并发指南3:并发三大问题与volatile关键字,CAS操作
查看>>
Java并发指南4:Java中的锁 Lock和synchronized
查看>>
Java并发指南5:JMM中的final关键字解析
查看>>
Java并发指南6:Java内存模型JMM总结
查看>>
Java并发指南7:JUC的核心类AQS详解
查看>>
Java并发指南8:AQS中的公平锁与非公平锁,Condtion
查看>>
Java网络编程和NIO详解6:Linux epoll实现原理详解
查看>>
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
查看>>
Java网络编程与NIO详解8:浅析mmap和Direct Buffer
查看>>
Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
查看>>
Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
查看>>
深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
查看>>
深入理解JVM虚拟机3:垃圾回收器详解
查看>>
深入理解JVM虚拟机4:Java class介绍与解析实践
查看>>
深入理解JVM虚拟机5:虚拟机字节码执行引擎
查看>>
深入理解JVM虚拟机6:深入理解JVM类加载机制
查看>>
深入了解JVM虚拟机8:Java的编译期优化与运行期优化
查看>>