1.4 互联网架构方法论
1.4.1 CAP模型
1.CAP理论
CAP是指任何分布式系统在可用性、一致性、分区容错性方面,不能兼得,最多只能得其二,因此,任何分布式系统的设计只是在三者中的不同取舍而已,如图1-1所示。
图1-1 CAP组合
■ C指Consistency,即一致性。一致性被称为原子对象,任何读写都应该看起来是“原子”的或串行的。写后面的读一定能读到前面写的内容,所有的读写请求都好像被全局排序。即更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致。
■ A指Availability,即可用性。对任何非失败节点都应该在有限时间内给出请求的回应。
■ P指Partition tolerance,即分区容错性。允许节点之间丢失任意多的消息,当网络分区发生故障时,节点之间的消息可能会完全丢失。即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
2.CAP的证明
2009年,CAP理论的提出者Brewer给出了一个比较简单的证明(见http://www.julianbrowne.com/article/brewers-cap-theorem)。
网络中有两个节点N1和N2,可以简单地理解N1和N2分别是两台计算机,它们之间的网络可以连通。N1中有一个应用程序A和一个数据库V,N2中也有一个应用程序B和一个数据库V。现在,A和B是分布式系统的两个部分,V是分布式系统的数据存储的两个子数据库。
如图1-2所示,分布式系统正常运转的流程为,用户向N1机器请求数据更新,程序A更新数据库V0为V1,分布式系统将数据进行同步操作M,将V1同步到N2中的V0,使得N2中的数据V0也更新为V1,N2中的数据再响应N2的请求。
图1-2 正常情况下的数据更新
如图1-3所示,假设在N1和N2之间网络断开的时候,有用户向N1发送数据更新请求,N1中的数据V0将被更新为V1,由于网络是断开的,所以分布式系统同步操作M失败,N2中的数据依旧是V0。这个时候,有用户向N2发送数据读取请求,由于数据还没有进行同步,应用程序没办法立即给用户返回最新的数据V1,此时有两种选择:第一,牺牲数据一致性,响应旧的数据V0给用户;第二,牺牲可用性,阻塞等待,直到网络连接恢复,数据更新操作M完成之后,再给用户响应最新的数据V1。
图1-3 网络错误情况下的一致性与可用性
这个过程证明,要满足分区容错性的分布式系统,只能在一致性和可用性两者中选择一个。
3.CAP理论的演化
CAP理论的主要贡献者是Brewer和Lynch。CAP理论也是在辩论过程中不断演化的,对CAP与分布式事务,CAP与响应时间的关系等概念不断完善。
2012年,Brewer就CAP理论再次撰文《CAP Twelve Years Later:How the"Rules"Have Changed》,文章最主要的观点是CAP理论并不是说三者必须选择两者。首先,只要是分布式系统,就可能存在分区,但分区出现的概率是很小的(否则就需要优化网络或者硬件),CAP在大多数时候允许完美的C和A,只有在分区存在的时间段内,才需要在C与A之间权衡。其次,一致性和可用性都是一个度的问题,不是0或者1的问题,可用性可以在0%到100%之间连续变化,一致性分为很多级别(比如在Cassandra中,可以设置consistency level)。因此,当代CAP实践的目标应该是针对具体的应用,在合理范围内最大化提升数据一致性和可用性。文章中还指出,分区是一个相对的概念,当超过了预定的通信时限,即系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
4.CAP的应用
CAP有三种组合模式,不同的组合模式适用于不同的业务场景。
(1)CA:优先保证一致性和可用性,放弃分区容错。如果不要求P(分区容错),则C(强一致性)和A(可用性)是可以保证的。这也意味着放弃系统的扩展性,系统不再是分布式的。如MySQL和Oracle就保证了可用性和数据一致性,但它们并不是分布式系统。其实分区错误始终会存在,无法通过降低CA来提升P,要想提升系统的分区容错性,需要通过提升基础设施的稳定性来保障。
2013年Lior Messinger在其文章《Better Explaining the Cap Theorem》中指出:在分布式系统中,网络分区一定会发生,因此仅需要在A和C之间权衡,即“it is really just A vs C!”。
(2)CP:优先保证一致性和分区容错性,放弃可用性。如果不要求A(可用),相当于每个请求都需要在节点之间强一致,而P(分区容错)会导致同步时间无限延长,如此CP是可以保证的。很多传统的数据库分布式事务都属于这种模式,在数据一致性要求比较高的场合是比较常见的做法,一旦发生网络故障或者消息丢失,就会牺牲用户体验,等恢复之后用户才逐渐能访问。
HBase是一个强一致性数据库,不是“最终一致性”数据库,在HBase的官方文档Architecture Overview中有说明(见https://hbase.apache.org/book.html#arch.timelineconsistent.reads)。
ZooKeeper是CP(一致性+分区容错性)的,即任何时刻对ZooKeeper的访问请求都能得到一致的数据结果,同时系统对网络分区具备容错性。但是它不能保证每次服务请求的可用性,也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果。ZooKeeper是分布式协调服务,它的职责是保证数据在其管辖下的所有服务之间保持同步、一致。所以就不难理解为什么ZooKeeper被设计成CP而不是AP特性的了。
(3)AP:优先保证可用性和分区容错性,放弃一致性。一旦分区错误发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。NoSQL中的Cassandra就是这种架构。与CP一样,放弃一致性不是说一致性就不保证了,而是逐渐变得一致。
对于多数大型互联网应用场景来说,集群规模大,节点故障、网络故障是常态,而且要保证服务可用性达到N个9,所以业务要设计成AP,舍弃C,退而求其次保证最终一致性。比如在电商秒杀活动中,当购买的时候提示有库存(实际可能已经没库存了),当去支付时,系统再提示库存不足。这其实就是先在可用性方面保证系统可以正常服务,然后在数据的一致性方面做了牺牲。在用户可以接受的前提下,网站舍弃的只是强一致性,退而求其次保证了最终一致性。下单的瞬间,库存可能存在数据不一致的情况,过程中对用户体验产生了影响,但是过了一段时间,还是要保证最终一致性的。
5.BASE理论
eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,提出BASE理论,BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consistency)。
BASE是指基本可用(Basically Available)、软状态(Soft State)、最终一致性(Eventual Consistency)。
基本可用:基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务,这就是损失部分可用性的体现。
软状态:软状态是指允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中,一般一份数据至少有三个副本,允许不同节点间副本同步的延时就是软状态的体现。
最终一致性:最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。
6.ACID
关系型数据库的事务操作遵循ACID原则,ACID原则是指在写入/异动资料的过程中,为保证交易正确可靠而必须具备的四个特性,即原子性(Atomicity,又称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)和持久性(Durability)。
原子性,即在事务中执行的多个操作是原子性的,要么事务中的操作全部执行,要么一个都不执行。
一致性,即保证进行事务的过程中整个数据库的状态是一致的,不会出现数据不一致的情况。
隔离性,即两个事务不会相互影响,覆盖彼此数据等。
持久性,即事务一旦完成,那么数据应该被写到安全的、持久化存储的设备上(比如磁盘)。
1.4.2 AKF Scale Cube扩展立方体
AKF Partners公司提出了Scale Cube,也就是AKF扩展立方体模型,是对应用横向扩展、纵向扩展理论的完整性的总结。这是一个包含X,Y,Z轴的三维模型(见https://akfpartners.com/growth-blog/scale-cube)。AKF扩展立方体理论模型如图1-4所示。
图1-4 扩展立方体
(1)X轴扩展
水平复制,复制同样的工作或数据镜像给多个实体,通过克隆的方式水平扩展。一般是在负载均衡后面放置多个相同的应用服务,如果有N个相同的应用部署,那么每个单独的应用只需要处理1/N份的负载请求。优点是简单易扩展。缺点是当单体应用本身的复杂性提高时所带来的管理及运维挑战,例如针对特定事件的处理需要对整个应用进行发布部署,同时数据库的水平复制存在挑战。
(2)Y轴扩展
功能分解,拆分不同的事务进行扩展。针对X轴扩展产生的问题,从Y轴这个方向扩展,将巨型应用拆解,分解为一组不同的服务,把分割的工作职责和数据分配给多个实体,这也是微服务理论诞生的基础。例如将购物应用分解为购物车服务、订单服务、支付服务等。优点是服务拆解以后便于维护和有针对性的扩展。缺点是按功能拆解以后,服务数量增多,部署成本增高;服务与服务之间调用传输成本增高;由内存调用转变为网络传输,故障率增高。
(3)Z轴扩展
数据分区,是指按照客户的需求、位置或者价值分割或分配工作职责,一般来说就是对数据的扩展,将事务产生的数据按照一定的特征分区在不同的服务器上。如按照客户ID进行分库分表。优点是对数据进行隔离,不同数据的请求被分发到不同的服务器上。缺点是Z轴扩展是所有扩展中复杂度最高的。
从传统的巨大的单体结构到如今面向服务的去IOE的架构,互联网核心架构的演变和发展就是在不断应用AKF扩展立方体模型。
三种扩展方式可以根据需要组合使用,但一定要选择与应用规模相符合的架构,例如一个面向小企业的企业内部信息系统就没必要进行Y轴扩展。