CAP理论是分布式系统构建中的基础理论之一,其中的C(Consistency),一致性即指所有的节点都能访问同一份最新的数据副本、A(Availability),可用性即指每个请求都能接收到一个响应,而P(Partition Tolerance),分区容忍性即指除了整个网络的故障外,其他的故障(集)都不能导致整个系统无法正确响应。CAP理论的核心即是一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。在笔者刚才描述的服务端应用程序构建的场景中,同样可以用类似于CAP理论的方式进行描述。
Partition Tolerance:在上文的描述中,我们业务系统构建的一个目标是在干净整洁的代码的基础上提供灵活多变的接口,这就好像饭店一样,如果我们为Consumer提供了一盘做好的黄焖鸡米饭,Consumer是很难再把它变成炒鸡杂。而如果我们提供的是原料食材,那么Consumer想做成什么都可以。封装程度越高的Service/API的可重用性与可组合性越低。笔者在上文提及,任何一个复杂的应用程序皆可以表示为简单的CURD操作的排列组合,而如果我们的Service层或者API层只提供最基本的,即粒度最小的操作,那么Controller层或者Consumer的自由组合的能力也就越强,整个应用系统的灵活性与可变性也就越高。总结而言,Partition Tolerance即是衡量一个服务端应用系统可以提供对外的API的粒度,粒度越低代表着分割容忍性越好。最极端的情况即是Server只提供最基本的CRUD操作,就好像只是对于数据库做了简单的封装。
Consistency:直观的说,如果我们以保证灵活性、可变性为目标,势必会减少对于数据库连接操作的使用。换言之,原本一条SQL语句连接查询获得的内容变成了执行两次SQL语句,这就导致了可能在两次查询的间隙数据已经发生了变化,最终导致返回给Consumer的数据存在不一致性。
Availability:在Server中,可用性即指某个API的性能,或者说是响应时间。如果要保证分割容忍性,势必会将原本可以一次执行的SQL语句分为多次,导致查询效率急剧下降,也就导致了可用性受到影响。而如果要保证一致性,那么可以使用事务的方式,同样会导致可用性的减小。
目前绝大部分的Server端的实现都是以CA为目标,即牺牲了分割容忍性,保证强一致性与可用性,这也是ACID理论的表现。很多情况下我们会发生某个API其实只是执行了某条及其复杂的SQL语句,该SQL语句可能连接查询了十几张表并且返回数据。这也就导致了API的可变性极差,你要修改API返回的某个字段也就意味着要修改最底层被执行的那个SQL语句,等于重新构建了一个新的API。如果我们的系统目标是保证CP,即牺牲可用性。那么我们可以引入事务或者锁,即在一个Session的多次查询中锁定全表,从而保证返回数据的一致性。如果我们的系统目标是保证PA,即牺牲一致性,那么最好的方式就是引入缓存机制,可以设置在固定时间或者事件触发的情况下再进行真实查询操作,其他情况下可以从缓存中获取数据,这样就能够较好地保证用户的响应时间。
随着分布式系统的发展,eBay工程师提出大规模分布式系统的实践总结,在ACM上发表文章提出 Bash 理论是基本可用、软状态和最终一致性。不要求实时一致性,但一定要实现最后一点。笔者目前秉持的在Server端的开发过程中也是遵循BASE理论,这在下面会有详细介绍,这里还是阐述下BASE的内涵:
基本可用(Basically Available)。分布式系统在故障时允许损失可用性,保证核心业务可用。音频直播或是做活动时,当业务量非常大的时候可以降级。做游戏也是,在战斗的时候最关心数值的增长,看了多少人都无所谓,缓解核心内容的压力。
软状态(Soft State)。允许系统中出现的中间状态,中间状态不会耽误可用性。在写代码、编程业务的设计上,必须容忍有一定的临时数据同步,考虑到全局锁和数据多版本的对比,把各个节点的相关数据都上锁,这是一个悲观锁,一旦写任务,其他人都能改我的数据,这是比较悲观的心态。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。