人人都想学架构(四)
本文是《从0开始学架构》专栏学习的第四篇,主要讲解高可用架构,本文记录的是第六节CAP,CAP是一个理论,有很多不同的版本,所以理解的时候非常困惑,我觉得作者这个版本讲解的很全面,结合留言,让我对它的理解更上一层楼了,理论毕竟是理论,也没有绝对的对与错,重要的是学会思路,以便解决问题。
什么是CAP,在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
分布式系统一定是有多个节点的,节点是互联的,共享代表某个节点有其他节点的数据(每个节点的数据不一定有全部数据)。按照这个理解,Memcached集群中每个节点数据都是独立的,所以不是CAP探讨的对象。
MySQL主从集群看上去算CAP探讨的对象,从写数据的角度看也能符合CA系统,可它是一个单点系统,如果遇到主库故障,则整个写服务就不可用了,如果是单点系统,这就不算一个分布式系统了(以上的领悟来源于留言,也是今天的收获)。
什么是一致性,首先要从 客户端 的角度去看,读操作保证能返回最新的写操作结果,其实一致性是CAP中最让人困惑的一个概念,专栏没有细说,最近在看《NoSQL精粹》这篇文章,讲的更全面。
CAP中的一致性表示线性一致性。最新的结果不代表节点之间数据是相同的,比如在更新一个事务的时候,某个节点拥有了最新的数据,但还没有提交,从这个角度看,其他节点没有办法获取未提交事务的数据。
什么是可用性,非故障的节点在合理的时间内返回合理的响应(reasonable response)。
客户端和节点之间如果有故障,这个和此处的非故障节点不是一回事,在分布式系统中,集群中的某个节点肯定会遇到故障,这个故障会影响其他非故障节点。
合理的响应表示没有错误或超时(如果不能连接其他节点或者连接超时则表示不具备可用性),但成功响应结果不代表是正确的(逻辑上)。
CAP中的可用性和高可用不一样,高可用是指部分实例挂了,能自动摘除,并由其它实例继续提供服务,关键是冗余。
什么是分区容忍性,当出现网络分区后,系统还能够“履行职责”,网络分区表示集群中某些节点不能和其他节点互通了,可能是丢包,也可能是连接中断,或者网络拥塞。履行职责和可用性是一致的,就是 reasonable response。
在分布式系统中,CAP中的P一定会发生,如果我们选择了 CA 而放弃了 P,那么当发生分区现象时,为了保证 C,系统需要禁止写入,当有写入请求时,系统返回 error(例如,当前系统不允许写入),这又和 A 冲突了,因此分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。关于这一点, 放弃P其实代表单点故障,MySQL主从是符合的,可分布式系统写入点不仅仅是一个节点,因为它们都是分片或分区的,那这个怎么牺牲?有个用户也留言了说牺牲P,说好说,怎么牺牲?理论和实践上还是有很长的路 。
什么是CP,见下图:
由于分区造成同步问题,为了保证P和C,系统必须告诉用户功能部分不可用,由于是不可用,间接说明客户不会遇到最新数据的问题了。
保证P,代表系统在分区的情况下还能提供部分功能。
什么是AP,见下图:
发生分区后,为了保证A,此时客户拿不到最新的数据,牺牲了C。
以上内容好像很好理解,但作者认为这些概念太抽象化了,省去了很多细节,在具体实践的时候,由于情况很复杂,很容易出现误解和偏差,所以下面说的才是重点。
1:CAP关注大力度是数据,而不是整个系统。
根据数据的不同应用场景,选择性的使用CP或者AP,不是说一个系统只能选择CP或AP。
2:CAP是忽略网络延迟的
可这个问题确实又存在,在分布式环境下无法做到完美,所以对于一些重要级别的操作(比如用户余额),在这种情况下,只能选择CA,也就是单点写入,其他节点做备份,无法做到 分布式下的多点写入 。(非常感谢,我读了很多遍才有了体会)。
关于这点感觉说的就是MySQL(其他的中间件我没想到)主从,对于单个用户余额来说无法应用分布式架构,可对所有用户来说还是一个分布式架构。比如北京的用户存在在北京,广州的用户存在在广州,两个城市有全量数据,在无法保证P的情况下(比如北京节点挂了),对于部分来说至少广州节点还能用,但对于单个用户来说他可能就完全不能使用了,个体是非分布式的,整体是分布式的。
3:正常的情况下,可以同时存在CA
在不考虑P的情况下(假设不会出现网络分区),不同级别的数据实现CA的方式也可以不一样,比如不重要的数据就使用“数据库同步”的方式(简单但延迟高),重要的数据使用队列的方式(复杂但实时性高)。
4:废弃并不等于什么都不做,需要为分区恢复做好准备。
分区并不是经常性发生,在恢复后,要尽量让系统恢复到CA。麻烦的就是某些数据可能会有冲突,需要想一些策略来同步数据。
和CAP相关的两个概念是ACID和BASE,ACID来是为了保证数据库事务性的,其实没有可比性。网络上有很多比较Redis和MySQL事务的文章,强行比较挺难为人的。这个后续我再参考资料后再分享。
对于BASE来说,它是CAP理论中AP方案的延伸,更具有实践性。
BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency),核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。
对于 基本可用 ,表示损失 部分 可用性,保证 核心 可用,部分和核心需要仔细分辨。
软状态,允许系统存在中间状态,而该中间状态不会影响系统整体可用性。这里的中间状态就是 CAP 理论中的数据不一致。
最终一致性,一定时间后数据最终一致,即达到CA。
BASE 理论本质上是对 CAP 的延伸和补充,更具体地说是对 CAP 中 AP 方案的一个补充
-
延迟是肯定存在的
-
AP 方案中牺牲一致性只是指分区期间,而不是永远放弃一致性。
这一节写的很精彩,留言更精彩,摘抄一段:
设计分布式系统的两大初衷:横向扩展(scalability)和高可用性(availability)。“横向扩展”是为了解决单点瓶颈问题,进而保证高并发量下的「可用性」;“高可用性”是为了解决单点故障(SPOF)问题,进而保证部分节点故障时的「可用性」。由此可以看出,分布式系统的核心诉求就是「可用性」。这个「可用性」正是 CAP 中的 A:用户访问系统时,可以在合理的时间内得到合理的响应。
为了保证「可用性」,一个分布式系统通常由多个节点组成。这些节点各自维护一份数据,但是不管用户访问到哪个节点,原则上都>应该读取到相同的数据。为了达到这个效果,一个节点收到写入请求更新自己的数据后,必须将数据同步到其他节点,以保证各个节点的数据「一致性」。这个「一致性」正是 CAP 中的 C:用户访问系统时,可以读取到最近写入的数据。
需要注意的是:CAP 并没有考虑数据同步的耗时,所以现实中的分布式系统,理论上无法保证任何时刻的绝对「一致性」;不同业务系统对上述耗时的敏感度不同。
分布式系统中,节点之间的数据同步是基于网络的。由于网络本身固有的不可靠属性,极端情况下会出现网络不可用的情况,进而将网络两端的节点孤立开来,这就是所谓的“网络分区”现象。“网络分区”理论上是无法避免的,虽然实际发生的概率较低、时长较短。没有发生“网络分区”时,系统可以做到同时保证「一致性」和「可用性」。
发生“网络分区”时,系统中多个节点的数据一定是不一致的,但是可以选择对用户表现出「一致性」,代价是牺牲「可用性」:将未能同步得到新数据的部分节点置为“不可用状态”,访问到这些节点的用户显然感知到系统是不可用的。发生“网络分区”时,系统也可以选择「可用性」,此时系统中各个节点都是可用的,只是返回给用户的数据是不一致的。这里的选择,就是 CAP 中的 P。
分布式系统理论上一定会存在 P,所以理论上只能做到 CP 或 AP。如果套用 CAP 中离散的 C/A/P 的概念,理论上没有 P 的只可能是单点(子)系统,所以理论上可以做到 CA。但是单点(子)系统并不是分布 式系统,所以其实并不在 CAP 理论的描述范围内。