相比关系型数据库,NoSQL解决方案提供了shared-nothing、容错和可扩展的分布式架构等特性,同时也放弃了关系型数据库的强数据一致性和隔离性,美其名曰:“最终一致性”。
最终一致性将读取不一致和不可靠的写带来的麻烦推给了软件开发人员。以如此弱的数据保证能力构建一个如今互联网需求的复杂、可扩展的系统是异常困难的,我们需要停止接受最终一致性,去探索能提供数据强一致性的可扩展的、分布式数据库设计。
最终一致性的概念频繁出现在分布式数据库的讨论中,主要的NoSQL数据库像Riak、Couchbase和DynamoDB,为客户端程序提供了“最终一致性”,MongoDB和Cassandra在一些配置中保证最终一致性。
最终一致性意味着:该系统最终一致——如果相当长的一段时间内,没有更新一个给定的数据项,最终,硬件和网络故障修复以后,所有该项目的读取都将返回相同一致的值。这也意味着:如果客户没有等足够长的时间,他们根本不能保证一致性。
最终一致性的问题
虽然最终一致性被吹捧为一种新的模式,但它同样有一定的负面含义,因为它不是在所有的情况下都很吸引人,这和分布式系统是一样的。
当一个工程师使用最终一致性数据库构建一个应用程序时,他们每次从数据库访问数据都要解决一些棘手的问题:
- 如果数据库读取返回一个任意的旧值对应用程序的影响是什么?
- 如果对数据库的修改顺序发生了错误对应用程序的影响是什么?
- 如果我在其他用户修改数据库时,读取数据对应用程序的影响是什么?
- 我的数据库更新对其它试图读取数据的客户有什么影响?
这是一个繁重的任务,并且占用大量的开发人员的时间。从本质上说,工程师需要手动去大量的工作,以确保多个用户不产生冲突和处理过期数据。
最终一致性带给软件开发者巨大的负担,在一个不能保证准确性的数据库上,设计一个准确的应用程序是一个巨大的挑战。谷歌最近发布的一篇关于其F1数据库的论文中指出了最终一致性的痛点:
谷歌在最终一致性系统方面有很多的经验。在所有这些系统中,我们发现开发人员花费相当一部分时间构建极其复杂且容易出错的机制来应对最终一致性和处理可能过时的数据。我们认为这是一个不可接受的强加给开发者的负担,并且一致性问题应该在数据库级别解决。
为什么是最终一致性?
构建一个最终一致性数据库有两个优势,一是构建一个弱一致性保证的系统更容易,第二个是从大型数据库机器中分割出来的数据库服务器仍然可以接受应用程序的写入。然而,第二个理由是由第一代NoSQL系统的创始人给出的,其可信度值得探究。
许多第一代NoSQL系统设计都是基于对Eric Brewer的CAP定理的早期理解:(C)onsistency、(A)vailability和(P)artition-tolerance三者只能满足两个。
这个定理适用于任何通信网络可能出错的分布式系统,根据这个原理,假设系统的可用性是必不可少的,早期的NoSQL数据库放弃了一致性(即采用了最终一致性)。
怎样解决这个问题?
CAP理论中的可用性,意味着每一个节点即使无法与系统其它部分通信时,仍然能够读取和写入。很容易看到可用性和一致性的矛盾:如果一个节点不能与其它任何节点通信,怎么能保持它们的一致性?
然而,一个优秀的备选方案是可能的:一个分区内部分结点可读写的系统是不可用的,从CAP理论来看是不可用的,但是从用户仍然能够与连接的节点进行交互的角度来说是可用的。可以构建这种没有单点故障的容错型数据库,而不是诉诸最终一致性。
处理最终一致性带来的麻烦不应该交给开发人员去处理。供应商应该停止以CAP定理作为理由来推崇最终一致性。新的分布式、一致的系统,例如谷歌的Spanner,在强一致性和高可用性之间演示了虚假的一种权衡。
下一代的商业分布式强一致性数据库虽然不容易构建,但它们将比它们的前任更加强大。像第一代,它们拥有真正的shared-nothing分布式架构、容错性和可扩展性。然而,相比最终一致性,他们也应该采取更强有力的模型如ACID,使他们在企业生产工具中更强大。