CAP理论


​ 使用了一段时间的Hbase,一直没有时间去了解它的理论基础。最近在看分布式的一些原理,其中最著名的分布式理论就是CAP理论,CAP理论是分布式系统的基石,CAP是Consistency(一致性)。 Availability(可用性)。Partition tolerance(分区容错性) 三个单词的首字母缩写。下面是百度百科上的解释。

● 一致性(C):所有的节点上的数据时刻保持同步

● 可用性(A):每个请求都能接受到一个响应,无论响应成功或失败

● 分区容错性(P):系统应该能持续提供服务,即使系统内部有消息丢失(分区)

CAP理论在互联网界有着广泛的知名度,一般系统架构师会把其作为衡量系统设计的准则。大家都非常清楚地理解了CAP:任何分布式系统在可用性、一致性、分区容错性方面,不能兼得,最多只能得其二,所谓鱼和熊掌不可兼得。因此,任何分布式系统的设计只是在三者中实现其中的两者。

1 . 发展

​ 所有理论都是从实际的经验中总结出来的,因此从实际的业务场景中去学习这些理论的原理也是最容易理解的。CAP理论的诞生也是技术发展的必然,在单机应用系统时代,一个系统会使用单节点的服务器做数据库,考虑的成本一般会使用开源中间件比如mysql。用户数据都存储在这台服务器上,开始一切都运转得很好,但随着用户的增长,突然有一天这台服务器挂了(宕机),导致mysql数据库不能对外提供服务了。虽然工程师能很快的修复了问题,但造成了不好的用户体验,究其原因是因为数据库在一台服务器上,会有单点故障的隐患。于是出现了把应用系统或是数据部署在多个节点上来避免单点故障的做法,提高了系统的可用性但是也会带来一系列问题,2000年,Eric Brewer教授在PODC的研讨会上提出了一个猜想:一致性、可用性和分区容错性三者无法在分布式系统中被同时满足,并且最多只能满足其中两个! 这个猜想首次把一致性、可用性和分区容错三个因素提炼出来作为系统设计的重要特征,断言用此三者可以划分所有的分布式系统,并指明这三个特征之间的不可能性关系。Brewer猜想比单纯的“低延迟和顺序一致性不能被同时满足”的结论更具体,对实际系统的构建也更具有可操作性! 于是就有了CAP理论,CAP的出现仿佛是一盏明灯,它揭露了分布式系统的本质,并给出了设计的准则,而这正是1985年以来人们正在寻找的东西!所以CAP在当时的影响力是非常大的!

2 . 解释

(1) . 数据一致性

由于在分布式系统中数据是存储在不同节点上的,必然就会带来数据一致性的问题,在集群中数据的一致性是指数据副本的一致性,与关系型数据库中强调的数据一致性是有区别的。在关系数据库中,数据的一致性是指事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。这是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性 。而分布式系统中的一致性是指,数据副本之间的一致性,对于一个将数据副本分布在不同分布式节点上的系统来说,如果对第一个节点的数据进行了更新操作并且更新成功后,却没有使得第二个节点上的数据得到相应的更新,于是在对第二个节点的数据进行读取操作时,获取的依然是老数据(或称为脏数据),这就是典型的分布式数据不一致的情况。在分布式系统中,如果能够做到针对一个数据项的更新操作执行成功后,用户都可以读取到其最新的值,那么 这样的系统就可以被认为具有强一致性,而在集群中一致性也是相对而言的。

  • 强一致性:这是最符合人的本能感官的,它要求数据写入后,立马能读到最新的数据,但对于分布式系统而言实现起来往往对系统的性能影响很大

  • 弱一致性:这种一致性级别是指系统在写入成功后,不承诺立即可以读到写入的值,,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态

  • 最终一致性:这其实也是弱一致性,算是弱一致性的一个特例,也是目前分布式系统中被广泛使用的一致性原则。它不保证数据多长时间能够达到一致性的状态,但保证无论多久数据最终能够达到一致性。

    在实际工程实践中,最终一致性存在以下五类主要变种。

    a.因果一致性:

    ​ 因果一致性是指,如果进程A在更新完某个数据项后通知了进程B,那么进程B之后对该数据项的访问都应该能够获取到进程A更新后的最新值,并且如果进程B要对该数据项进行更新操作的话,务必基于进程A更新后的最新值,即不能发生丢失更新情况。与此同时,与进程A无因果关系的进程C的数据访问则没有这样的限制。

    b.读己之所写:

    ​ 读己之所写是指,进程A更新一个数据项之后,它自己总是能够访问到更新过的最新值,而不会看到旧值。也就是说,对于单个数据获取者而言,其读取到的数据一定不会比自己上次写入的值旧。因此,读己之所写也可以看作是一种特殊的因果一致性。

    c.会话一致性:

    ​ 会话一致性将对系统数据的访问过程框定在了一个会话当中:系统能保证在同一个有效的会话中实现“读己之所写”的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。

    d.单调读一致性:

    ​ 单调读一致性是指如果一个进程从系统中读取出一个数据项的某个值后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。

    e.单调写一致性:

    ​ 单调写一致性是指,一个系统需要能够保证来自同一个进程的写操作被顺序地执行。

    最终一致性并不是只有那些大型分布式系统的专属,许多现代的关系型数据库都采用了最终一致性模型。主要体现在数据库的主从热备,读写分离等场景,大多都会采用同步和异步方式来实现主备数据复制技术。在同步方式中,数据的同步通常是写在一个事务中,因此在事务完成后,主备数据库的数据就会达到一致。而在异步方式中,备库的更新往往存在延时,这取决于网络IO的时间,如果时间过长或者甚至在日志传输过程中出现异常导致无法及时将事务应用到备库上,那么很显然,从备库中读取的的数据是旧的,因此就出现了不一致的情况。无论是采用多次重试,关系型数据库还是能搞保证最终数据达到一致——这就是系统提供最终一致性保证的经典案例。

(2) . 可用性

可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。这里的重点是”有限时间内”和”返回结果”。”有限时间内”是指,对于用户的一个操作请求,系统必须能够在指定的时间内返回对 应的处理结果,比如一秒或是五秒,如果超过了这个时间范围,那么系统就被认为是不可用的。另外,”有限的时间内”是指系统设计之初就设计好的运行指标,通常不同系统之间有很 大的不同,无论如何,对于用户请求,系统必须存在一个合理的响应时间,否则用户便会对系统感到失望。”返回结果”是可用性的另一个非常重要的指标,它要求系统在完成对用户请求的处理后,返回一个正常的响应结果。即成功或失败,而不是一个让用户感到困惑的返回结果。

(3) . 分区容忍性

这个词单从字面上有点难以理解它的意思,我的理解:在分布式系统中会出现一些局部小集群,这些局部网络的节点与集群中正常的节点不能通信,导致数据出现不一致的情况。举个例子,假设100个节点的集群,其中有20个节点由于网络波动或是其它原因,导致这20个节点不能与另外的80个节点通信,我们称这20个节点是一个局部小集群(专业术语称之为网络分区,实际情况集群可能出现多个网络分区)。由于不能通信导致,用户在向集群中存储数据时,这20节点不能同步集群的数据而出现数据不一致的情况。分区容忍性描述的就是这种情况,所谓容忍性就是在设计集群时,容忍或是不容忍出现这种情况,如果不容忍是牺牲了可用性,因为集群一旦出现网络分区,则意味着集群必须实现数据的一致性,这会使得集群一直等待,直到集群中那20个节点数据同步完成,这个等待的时间也是不确定的,意味着牺牲了集群的可用性。如果容忍出现这种情况,容忍的程度是多大,而且需要采取一定的策略在那20个节点正常通信后,完成集群的数据同步,这里则是牺牲了数据的一致性,而提高了集群的可性。

3 . 分布式环境的各种问题

1、网络分区

当网络由于发生异常或波动情况,导致分布式系统中部分节点之间的网络延时不断增大,导致整个集群节点中,只有部分节点之间能够正常通信,而另一些节点则不能,我们将这个现象称为网络分区。当网络分区出现时,对集群的数据一致性,数据的事物处理,造成了非常大的挑战

2、节点故障

节点故障则是分布式环境下另一个比较常见的问题,指的是组成分布式系统的服务器节点出现的宕机或”假死”现象,通常根据经验来说,每个节点都有可能出现故障,并且每天都在发生

3、三态

在传统单机系统中,应用程序处理请求只有两种状态,要么成功,要么失败。而在集群中则多了一种状态超时,而且超时是一个非常普遍的现象,出现超时现象,通常有以下两种情况
(1)由于网络原因,该请求并没有被成功地发送到接收方,而是在发送过程中就发生了消息丢失现象
(2)该请求成功地被接收方接收后,进行了处理,但是在将响应反馈给发送方的过程中,发生了消息丢失现象
当出现这样的超时现象时,网络通信的发起方是无法确定当前请求是否被成功处理。因而在集群设计之初就必须假定集群中节点是不稳定的,网络是不可靠的,这样才能设计出一个良好的分布式系统,在很多分布式框架中如Kafka,Zookeeper都有类似情况的处理方式,值得借鉴。

4 . CAP的权衡

选择 说明
CA 放弃分区容错性,加强一致性和可用性,就是传统的单机数据库的选择
AP 放弃强一致性,追求分区容错性和可用性,这是很多分布式系统设计时的选择,如NOSQL
CP 放弃可用性,追求一致性和分区容错性

Author: 顺坚
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 顺坚 !
评论
 Previous
Http请求中转 Http请求中转
​ 在工作中碰到需要在服务端中转Http请求的需求,一般的请求其实问题不大,用apache的HttpClient 提供的jar包即可解决问题,但是带文件上传的请求中转,遇到了一些小麻烦,在此记录一下。 业务场景是这样的,由于是做系统升
2018-06-30
Next 
虚拟机指令集 虚拟机指令集
​ Java虚拟机既然是一台虚拟的计算机,那必有一套完善指令集,指令由一个字节长度,代表某种特定操作含义的操作码构成。这里在最初接触计算机的时候,我是有一些疑问的。例如为什么计算机都有它的指令集,这些指令是怎么被CPU执行的。由于我当
2018-06-10
  TOC