1.0分布式原理——ACID vs BASE vs CAP

CAP:首先EricBrewer,aprofessorattheUniversityofCalifornia,Berkeley,andcofounderandchiefscientistatInktomi提出了CAP理论:CAP:Consistency,AvailabilityandToleranceofnetworkPartition。并证明了CAP最多只能同时满足两个。HepresentedtheCAPtheorem,whichstatesthatofthreepropertiesofshared-datasystems—dataconsistency,systemavailability,andtolerancetonetworkpartition—onlytwocanbeachievedatanygiventime.Amoreformalconfirmationcanbefoundina2002paperbySethGilbertandNancyLynch.那么如果要满足all-or-nothing的原子性和强一致性,这也是ACID事务所要满足的需求,就不得不牺牲可用性。如果想要获得可用性和P(toleranceofnetworkpartition).那就不得不牺牲一致性,也就不存在原子性,这也就是BASE所能满足的需求。

ACID:Atomicity,Consistency,Isolation,Durability.

BASE:BasicAvailable,Soft-state,EventualConsistency.

EricBrewer这里的C值得不是ACID中的一致性,而是原子性。

CAP

证明为什么CAP不能三个同时满足

TheProofinPictures

在NetworkN1和N2中分别有两个nodeA和B,这两个节点上面都包含数据V0(天龙八部在货仓中的数目)。

在某一个星期日,A将自己的数量从V0更新到V1,并通知B,更新到V1。这样任何从B读出的书的数目也是V1。

如果网络出现分区则A更新到V1之后B仍然是V0。

开始讨论了:1)如果不考虑分区耐受性,那么很简单N1只需要将自己更新而不需要考虑N2,当有消息的时候只需要读取A。如果A失败了那么网络也就失败了。这相当于一个单机系统那么是可以保证Consistency&Availability的。2)如果要保证分区耐受性,也就是也能够从B读取数据。如果牺牲Availability,那么更新数据的时候A使用两阶段提交协议将B锁住就可以保证A和B的数据是一致的。或者说存在另外的一个Coordinator用两阶段提交协议更新数据,将A和B都锁住。如果牺牲一致性,那么就可以直接更新A和B而不需要考虑是否满足consistency。

假设有这样的一个transaction,a1阶段write,a2阶段read。如果实在一个单机系统上,通过简单的写锁是可以控制系统的一致性和可用性的,只是需要尽量缩短synch的时间。但是在分布式系统里面,由于各种原因很难控制synch的时间。我们只能控制什么时候a2开始,但是我们不能保证在a2开始的时候一定能读到a1写的数据。

ACID

满足ACID属性又被称为是事务,被广泛应用在以数据库为代表的对可靠性和安全性有极高需求的应用场景。单对于Atomicity(原子性)数据库领域和操作系统领域的理解是有相应差异的。在数据库领域原子性指的是all-or-nothing的原子性,而操作系统是指一个操作在没有完成之前是不能被其他操作干预的,实际上是isolation的原子性。原子性和隔离性又是实现一致性的基础。

持久性满足当对数据提出需求时,数据扔然能够被正常读取。根据不同的场景,对持久性提出了不同程度的要求。计算机的一条指令只需要寄存器级别的持久性,运行程度的中间变量需要的是内存级别的持久性,而文件系统需要硬盘级别的持久性,为了获得更高级别的持久性,并防止因为硬盘故障或者是网络故障导致的无法正常读取数据的问题,产生了将数据分片存储的需求(如RAID)。或者将数据备份如(Master-Slave架构)。

对于采用分片或者M-S结构的持久性实现方式,对于一致性提出了新的挑战。在某种程度上可以认为,分布式系统的一致性问题的根源来源于为了保证系统的持久性也就是可靠性。

BASE

研究BASE就需要和REST做对比,因为这是衡量一个互联网应用的准则。不同于ACID面相的商业应用,互联网应用对可用性的要求更高,而对可靠性的要求在某种意义上要比商业应用低。

BASE的应用场景

你是怎样为像“出价竞拍”这样的操作实现原子性的?

出价竞拍本身就是一个很有意思的问题,原子性并不是重点,更多的是关系到在拍卖关键的最后几秒钟里不要阻塞任何出价人。如果改成在显示时刻而不是在出价时刻计算最高出价人和最高出价,就会变得非常简单。所有出价都被插入到一个单独的子表,插入操作不太会引起资源争用的情况。每次显示产品的时候,再重新取回所有的出价,并且在这个时候应用业务逻辑来决定最高的出价人。

你的问题背后隐藏的真正问题是我们如何实现一致性?要在大型系统中实现一致性,你必须放弃ACID,转而使用BASE:

基本可用(BasicallyAvailable)

软状态(Softstate)

最终一致(Eventuallyconsistent)

如果你能够在每个客户端请求快结束的时候放松对数据一致的要求,就有可能消除分布式事务,并使用其它机制来达成一致的状态。举例来说,在上面的出价案例中,我们也更新视图数据表,视图数据表是按照出价人来组织数据的,目的是加速“我的eBay”页面的显示。这里用两个异步事件来完成。一个是依靠内存中的队列,因为我们希望尽量缩短从出价到在显示在“我的eBay”页面上之间的响应时间。但是,内存中的队列不可靠,所以在发生出价操作的时候,我们同时用一个服务器端事务来捕获出价事件。即使内存中队列的操作失败了,这个出价事件也能根据还原机制被处理。出价人视图数据表因此而解耦,但不总是与出价表的状态保持一致。不过这是我们可以接受的让步,它让出价表和出价视图表之间不必服从ACID要求。

相关推荐