1.4 数据一致性

在大数据系统中,为了获得系统可用性,需要为同一数据分片存储多份副本,业界的常规做法是一个数据分片同时保存三个副本。将数据复制成多份除了能增加存储系统的可用性,同时还能增加读操作的并发性,但引发了数据一致性问题,即同一数据分片存在多个副本。在并发的写请求下,如何保持数据一致性尤为重要,即在存储系统外部的使用者看来,即使存在多个副本数据,它与单份数据也应该是一样的。

CAP、BASE、ACID等基本原则是分布式环境下数据一致性方案设计重要的指导原则。

1.4.1 CAP原则

CAP是对Consistency/Availability/Partition Tolerance的一种简称,CAP原则对分布式系统中的三个特性进行了如下归纳。

●一致性(Consistency):在分布式系统中的所有数据备份,在同一时刻是否具有同样的值(等同于所有节点访问同一份最新的数据副本)。

●可用性(Availability):在集群中,一部分节点出现故障后,集群整体是否还能响应客户端的读写请求(对数据更新具备高可用性)。

●分区容错性(Partition Tolerance):从实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

CAP原则是指对于一个大规模分布式数据系统来说,CAP三个特性不可兼得,同一个系统至多只能实现其中的两个,而必须放宽第三个要素来保证其他两个要素被满足。即要么AP,要么CP,抑或AC,但是不存在CAP,如图1-1所示。

图1-1 CAP原则示意

我们可以认为,在网络环境下,运行环境出现网络分区是不可避免的,所以系统必须具备分区容忍性特性,于是,一般在此种场景下,设计大规模分布式系统时,架构师往往在AP和CP中进行权衡和选择,有所强调、有所放弃。

在一个分布式系统中,如果数据无副本,那么系统首先就满足强一致性条件,单一副本数据,不可能发生数据不一致的情况。此时,系统具备C,如果我们容忍分区容错性P,意味着系统可能发生网络分区状况,如有宕机现象出现时,就必然导致某些数据不可访问,此时,可用性A是不能被满足的,即在此情形下获得了CP特性,但CAP不可同时满足。

如果系统中数据有副本,假设一份数据有分别存储在不同机器上的两个副本,最初数据是保持一致的,某一时刻,机器1上对这个数据进行了更新操作,这个更新操作随后会同步到机器2上,使两个副本保持一致性。但网络分区是不可忽视的,可以设想,在数据复制同步未完成的情况下,发生了网络分区,导致两台机器无法通信,这时,我们就不得不在C或A之间做权衡和选择。如果希望系统可用性优先(选择A),那么对于读取机器2上的数据查询请求返回的并非是最新的数据,此种选择就放弃一致性(C),产生数据不一致情况。如果选择一致性优先(选择C),那么,在两台机器恢复通信并将数据同步到一致状态前,对于机器2就要拒绝对数据的读请求,此时,可用性无法保证(放弃A)。所以不论选择哪一个,必然以牺牲另外一个因素作为代价,也就是说,要么AP,要么CP,但不会有CAP。

对于分布式系统来说,分区容错性是天然具备的,所以在设计具体分布式架构技术方案时,只能对一致性和可用性两个特性做出取舍,要么选择强一致性,减弱服务可用性,要么选择高可用性而容忍弱一致性。

我们可以回顾一下传统关系数据库的ACID特性,在CAP三要素中,传统关系数据库选择CA两个特性,即强一致性、高可用性,与分区容错性这个天然要素不可调和,这是造成其在分布式环境下可扩展性差的根本原因。而NoSQL系统则更关注AP因素,即高可用性和分区容错性,也意味着兼顾高可用性和高可扩展性,而牺牲强一致性。对于绝大多数互联网应用来说,高可用性直接涉及用户体验,而对数据一致性要求并不高,NoSQL系统这类以弱一致性作为代价的系统,正是适应了这一现实需求。

网络分区(P)虽然是个天然属性,但在现代的实际系统中,依然是个小概率事件。以此为出发点,我们并不应该为了容忍这种小概率事件而在设计之初就选择放弃A或者放弃C,在大多数没有出现网络分区的状况下,还是可以尽可能兼顾AC两者,即有条件地兼顾CAP三要素。

另一个需要说明的是,即使必须在AC之间做出取舍,也不应该是粗粒度地在整个系统级别进行取舍,即整个系统要么取A舍C,要么取C舍A,而是应该考虑系统中存在不同的子系统,甚至应该在不同的系统运行时或者在不同的数据间进行灵活的差异化的细粒度取舍,即可能对不同子系统采取不同的取舍策略,在不同的系统运行时,对不同数据采取不同的取舍策略。因此,CAP三者并非是绝对的两要素有或没有,可以看作是在一定程度上的有或没有,考虑的是在多大程度上进行取舍。

由此可以看出,CAP的修改策略是可取的。在绝大多数系统未产生网络分区的情形下,应该尽可能保证AC两者兼得,也即大多数情况下,考虑CAP三者兼得,当发生网络分区时,系统应该能够识别这种状况并对其进行正确处理,在网络分区场景下进入明确的分区模式,此时,可能会限制某些系统操作,最后,在网络分区解决后,能够进行善后处理,即恢复数据的一致性,或者弥补分区模式中产生的错误。

1.4.2 CAP与ACID

谈到CAP与ACID之间存在的关系,首先因为CAP和ACID两者都包含了A和C,但是其具体含义有所不同;其次,如果CAP中选择A的话,在一定程度上,会影响ACID中的部分要求。

CAP与ACID两者中尽管都包含一致性,但是,两者的含义不同,ACID中的C指的是对操作的一致性约束,而CAP中的C指的是数据的强一致性(多副本对外表现类似于单副本),所以,可以将CAP中的C看作一致性约束的一种,即CAP中的C是ACID中的C所涵盖语义的子集。在出现网络分区的情形下,ACID中的C所要求的一致性约束是无法保证的,所以,在网络分区解决后,需要通过一定手段来恢复ACID中要求的一致性。

当出现网络分区时,ACID中的事务独立只能在多个分区中的某个分区执行,因为事务的序列化要求通信,而当网络分区时,明显无法做到这点,所以只能在某个分区执行。如果多个分区都可以各自进行ACID中的数据持久化(D)操作,当网络分区解决后,如果每个分区都提供持久化记录,则系统可以根据这些记录发现违反ACID一致性约束的内容,并给予修正。

1.4.3 BASE原则

关系数据库系统采纳ACID原则,获得高可靠性和强一致性。而大多数分布式环境下的云存储系统和NoSQL系统则采纳BASE原则。BASE原则具体是指如下几项。

●基本可用(Basically Available):在绝大多数时间内,系统处于可用状态,允许偶尔的失效,所以称为基本可用。

●软状态或者柔性状态(Soft State):是指数据状态不要求在任意时刻都完全保持同步,可以理解为系统处于有状态(State)和无状态(Stateless)之间的中间状态。

●最终一致性(Eventual Consistency):与强一致性相比,最终一致性是一种弱一致性,尽管软状态不要求任意时刻数据保持一致同步,但是,在给定时间窗口内,最终会达到一致的状态。

BASE原则与ACID原则有很大的差异。BASE通过牺牲强一致性来获得高可用性。尽管现在大多数的NoSQL系统采纳了BASE原则,但是有一点值得注意:NoSQL系统与云存储系统的发展过程正在向逐步提供局部ACID特性发展,即从全局而言,符合BASE原则,但局部上支持ACID原则,这样,就可以吸取两者各自的好处,在两者之间建立平衡。

ACID强调数据的一致性,这是传统数据库设计的思路。而BASE更强调可用性,弱化数据强一致性的概念,这是互联网时代对于大规模分布式数据系统的一种需求,尤其是其中的软状态和最终一致性。可以说,ACID和BASE原则是在明确提出CAP理论之前关于如何对待可用性和强一致性的两种完全不同的设计思路。