分布式系统CAP

来源:互联网 发布:特斯拉model3知乎 编辑:程序博客网 时间:2024/04/30 16:20

维基百科:在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:[1][2]

  • 一致性(Consistency)(所有节点在同一时间具有相同的数据)
  • 可用性(Availability)(保证每个请求不管成功或者失败都有响应)
  • 分隔容忍(Partition tolerance)(系统中任意信息的丢失或失败不会影响系统的继续运作)



要真正理解 CAP 理论必须要读懂它的形式化描述。 形式化描述中最重要的莫过于对 Consistency, Availability, Partition-tolerance 的准确定义。 

Consistency (一致性) 实际上等同于系统领域的 before-or-after atomicity 这个术语,或者等同于 linearizable (可串行化) 这个术语。具体来说,系统中对一个数据的读和写虽然包含多个子步骤并且会持续一段时间才能执行完,但是在调用者看来,读操作和写操作都必须是单个的即时完成的操作,不存在重叠。对一个写操作,如果系统返回了成功,那么之后到达的读请求都必须读到这个新的数据;如果系统返回失败,那么所有的读,无论是之后发起的,还是和写同时发起的,都不能读到这个数据。 

要说清楚 Availability 和 Partition-tolerance 必须要定义好系统的故障模型。在形式化证明中,系统包含多个节点,每个节点可以接收读和写的请求,返回成功或失败,对读还要返回一个数据。和调用者之间的连接是不会中断的,系统的节点也不会失效,唯一的故障就是报文的丢失。 Partition-tolerance 指系统中会任意的丢失报文(这和“最终会有一个报文会到达”是相对的)。 Availability 是指所有的读和写都必须要能终止。 

注: “Availability 是指所有的读和写都必须要能终止” 这句话听上去很奇怪,为什么不是“Availability 是指所有的写和读都必须成功”? 要回答这个问题,我们可以仔细思考下“什么是成功”。“成功”必须要相对于某个参照而言,这里的参照就是 Consistency。 

CAP 理论说在一个系统中对某个数据不存在一个算法同时满足 Consistency, Availability, Partition-tolerance 。 注意,这里边最重要和最容易被人忽视的是限定词“对某个数据不存在一个算法”。这就是说在一个系统中,可以对某些数据做到 CP, 对另一些数据做到 AP,就算是对同一个数据,调用者可以指定不同的算法,某些算法可以做到 CP,某些算法可以做到 AP。 

要做到 CP, 系统可以把这个数据只放在一个节点上,其他节点收到请求后向这个节点读或写数据,并返回结果。很显然,串行化是保证的。但是如果报文可以任意丢失的话,接受请求的节点就可能永远不返回结果。 

要做到 CA, 一个现实的例子就是单点的数据库。你可能会疑惑“数据库也不是 100% 可用的呀?” 要回答这个疑惑,注意上面说的故障模型和 availability 的定义就可以了。 

要做到 AP, 系统只要每次对写都返回成功,对读都返回固定的某个值就可以了。 

如果我们到这里就觉得已近掌握好 CAP 理论了,那么就相当于刚把橘子剥开,就把它扔了。 

CAP 理论更重要的一个结果是, 在 Partial Synchronous System (半同步系统) 中,一个弱化的 CAP 是能达到的: 

* 对所有的数据访问,总返回一个结果 
* 如果期间没有报文丢失,那么返回一个满足 consistency 要求的结果。 

这里的半同步系统指每个节点存在一个时钟,这些时钟不需要同步,但是按照相同的速率流逝。更通俗的来说,就是一个能够实现超时机制的系统。 

举个例子,系统可以把这个数据只放在一个节点上,其他节点收到请求后向这个节点读或写数据,并设置一个定时器,如果超时前得到结果,那么返回这个结果,否则返回失败。 

更进一步的,也是最重要的,实现一个满足最终一致性 (Eventually Consistency) 和 AP 的系统是可行的。 现实中的一个例子是 Cassandra 系统。 



对CAP的探讨

 

  CAP理论是Eric Brewer教授在20世纪初提出来的,后来,经Seth Gilbert 和 Nancy lynch两人证明是正确的。我们知道,CAP代表了Consistency一致性,Availability可用性,Tolerance of network Partition分区容忍性,其代表的含义并不复杂,就是说:一个分布式系统不可能同时满足一致性,可用性和分区容忍性这三个需求,最多只能同时满足两个。要注意的是,我们这里都是讲分布式系统的,也就是说,根据CAP理论,要拿NoSQL数据库与关系数据库比较,也只能是和TeraData,GreenPlum,Netezza等分布式系统相比才有意义。

   很显然,根据CAP理论,抛开技术细节,从宏观来讲,关系数据库的设计目标,就是因为必须要很好的满足一致性C与可用性A,因此,便不能很好的满足分区容忍性P。所带来的结果,直观来讲,就是影响了其良好的水平扩展能力。正如我们上一章所讲的那样,对那些采用Shared Nothing的、MPP架构的、适用于OLAP场景的关系数据库,虽然从物理架构角度来讲其水平扩展性已经是很好了,但由于从软件角度还必须同时保证C与A的要求,导致其水平扩展性能相对NoSQL来讲,毕竟是有限的。

   关于CAP理论,其实有很多资料都有描述,大体来讲,都是很容易理解的:对可用性Availability一般认为主要是指系统的可靠性,比如节点宕机后对系统读写的影响,我们可能会要求这时系统还能继续正常读写;但这里认为,CAP理论中的可用性,还应该包括了高性能,即读写效率,因为很明显,我们设计NoSQL数据库,在牺牲了某方面特征后,需要得到的不只是与分区容忍性有关的水平扩展性,更重要的还有很高的读写性能。分区容忍性Tolerance of Partition就不用说了,自然是指水平扩展方便。最重要的就是关于一致性consistancy,这里认为很多资料都没有讲清楚。现在大多NoSQL的技术资料,都会将一致性的相关示例集中在一种场景下解释:即当同一数据有多个备份时,读与写的一致性(读写一致性是指:当写操作确认完成时,所有的读操作都能返回同样的结果;写操作要保证所有关联操作都完成时,才能真正确认完成),其实这样对一致性的理解是不全面的。我们知道在关系数据库事务操作ACID特性中的一致性C,主要是指一个事务中相关联的数据在事务操作结束后是一致的,例如银行一个存款交易事务,将导致交易流水表增加一条记录,同时,必须导致账户表余额发生变化,这两个操作必须是在一个事务中全部完成,以保证相关数据的一致性;当然,ACID中的C也也包括了对一个数据多个备份的读写一致性。我们说,CAP理论中的C与ACID中的C其实是一回事,只是因为大多数NoSQL数据库并不提供事务的功能,因此,关联数据一致性的问题,在NoSQL数据库的设计中并没有明显表现出来而已(如果基于NoSQL的应用,要实现这种特性,大多必须在应用中自行完成,或者借助其它工具完成,如HBase就借助zookeeper来实现锁功能),但并不是不存在这个问题,在NoSQL应用开发中你必须清楚:数据库本身除了对多备份数据一致性的支持外,在这方面不见得能支持你,当然还包括ACID机制中能保证的脏读,不可重复读,幻觉读等问题。所以,对一致性C全面的解释应该是包括以下两个方面:

   . 一个数据操作成功完成,必须保证该数据多个备份的读写一致性;

   . 一个数据操作成功完成,必须保证有关联关系的数据的读写一致性。

    现在,我们把按这样的要求实现的一致性称强一致性,因为在NoSQL数据库出现之前,我们谈一致性,都是缺省指强一致性。但现在,在NoSQL中,可能会通过牺牲一致性C,来得到可用性A与分区容忍性P,那么,NoSQL所谓牺牲一致性,其实是指不要求实现那么强的一致性,也就是弱一致性,或最终一致性。

    一致性C搞清楚后,我们再来看看可用性A的相关问题。我们说分区容忍性P保证后,C与A就变成冲突的了,为什么呢?很明显,如果保证C,要求一个写操作,要在多个备份上全部完成或相关操作全部完成后才确认,那么,在这个写操作完成之前的读操作,都是拿不到最新数据的。我们要么就是通过锁机制来防止读操作的进行,要么就是返回旧的数据(当然还要参考多版本并发控制MVCC机制),这样首先是对读写效率产生了影响;其次,一个写失败或读失败都会导致系统不可用的结果;而针对上面说的关联数据问题,如果在分布式系统中采用两段式提交很显然是使可用性A极大的降低,总之,可用性A是不高的;反之亦然。

    另外,我们还要清楚,如果抛开读与写的协调问题,单说读或者写的性能,先不要说读写操作不经过SQL解析本身就可以在很大程度上提供效率,NoSQL数据库也设计了很多其它措施来提高效率,而这些却是与CAP理论无关,这也就是我们说CAP与BASE理论其实并不能完整体系化的支撑NoSQL发展的原因。

    有了CAP理论,现在,再来看看NoSQL。如果我们说传统关系数据库的相关问题是因为保证了C与A,就不能保证P而引起的,那么通过NoSQL数据库来解决关系数据库瓶颈的方法,只能通过在C、A、P三个要素中选择其它两个来完成,因为我们不可能同时选三个。很简单,要么是选C与P,要么是选A与P,也就是说,你设计一个NoSQL数据库时,首先必须保证分区容忍性P,即要保证很好的水平可扩展性以达到对海量数据管理的要求(这几乎已经成为所有NoSQL数据库的共同特性了),然后,再根据需求选择C或者A,都是可以的,就如前面介绍的HBase就选择了C,而Cassandra则选择了A一样。

    这里还有一点很有必要指出:我们说为了保证一致性C会导致分布式系统的分区可容忍性降低,其本质是什么呢?相信对很多读者来说,这一点还不是很清晰的推导过程。其实如果我们将上面所说一致性C两个要素中的数据多备份情况的本质也归纳为分布式系统中的数据关联问题,那么,就可以这样说:分布式系统中严格要求的数据关联操作会在很大程度上限制其水平扩展性能。这样一来,就很好理解了,正如Join这样的操作一直都是分布式数据库的难点一样,这应该是同样的道理:关联问题在很多情况下不是并行处理的优点所在!这在很大程度上与Amdahl定律相符合!



0 0
原创粉丝点击