相比于SQL领域Mysql的风靡来说,NoSQL(Not only SQL)领域的发展简直是各领风骚啊,其按照存储模式都可以分为键值、列族、文档和图等四种,例如比较 常见的键值对数据库如redis,列族数据库HBase,文档数据库MongoDB等。虽然这些非关系型的数据库在自己擅长的领域各展所长,但是由于在分布式系统上实 现ACID太难,所以它们几乎都没有提供ACID的事务保证,它们的共同基础是分布式领域的两个著名理论,即CAP和BASE。

还是先来回顾一下关系型数据库事务的原则ACID:

  • A(Atomicity):原子性,指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生;

  • C(Consistency):一致性,指事务前后数据的完整性必须保持一致,数据库的完整性约束没有被破坏;

  • I(Isolation):指多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离;

  • D(Durability):指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响;

再来看一下CAP理论,其内容是:在分布式系统中,不可能同时满足一致性(consistency)、可用性(availability)、分区容忍性性(partition tolerance) 三大特征,最多只能同时满足其中二者。其中:

  • 一致性:指对于客户端向分布式系统的读请求,要么读到最新的数据,要么失败;

  • 可用性:指对分布式系统的请求一定会得到非错误的响应,但不保证响应一定包含最新写入的数据;

  • 分区容忍性:指即使分布式系统内部节点之间的通信出了问题,系统仍然能正常运作;

由于在分布式系统中,网络延迟、丢包等现象几乎肯定会出现,因此CAP中的分区容忍性必须要保证,所以对于一致性和可用性就必须要有所牺牲。这个意思并不 是说分布式系统中一定就无法保证一致性或可用性了,而是说当分布式系统由于网络丢包或延迟或其它问题而产生网络分区时,此时需要对一致性和可用性作出取 舍。因为出现网络分区情况时,如果优先保证一致性,也就是所有分区都必须返回相同的结果,那么由于网络分区之间暂时无法进行数据同步,那么就必须对这期 间所有的请求返回错误或不返回,否则就会返回不一样的结果而违反一致性原则。同理,如果优先保证可用性,也就是部分节点可用,由于网络分区的存在,各个 分区间的数据必定出现不一致。所以CAP原则并不是说一定只能三选二,而是指在出现异常导致分区P的情况下,是优先保证A服务可用,还是优先保证C数据一致。

就我们比较熟悉的HBase数据库来说,它是选择了CP,也就是当出现网络分区时,优先保证一致性而不是可用性,这也很好理解,毕竟HBase更多的时候是作为一 个数据库而存在,而数据库最重要的就是数据一致性,不然这个数据库有什么用呢?所以它会在出现异常时,对异常的RegionServer进行WAL重放且在此过程中 无法访问。当然了,HBase 2.0+版本支持的Region Replica特性可以使其在出现网络分区时,优先保证可用性而不是一致性。

很明显,CAP理论有时候太过于狭窄和一刀切,实际上很多时候我们既想满足可用性需求,也可以忍受分布式系统暂时的不一致性,只要它能在经过一定的时间后 恢复到一致的状态就是可以接受的。另外,可用性要求所有的节点都能响应请求,有时侯这只是一种理想的状态,在真实的世界中由于各种不可预计的原因,是很 难满足这样苛刻的条件的。

于是,BASE理论出现了,它的含义是:

  • BA(basically available):基本可用,指分布式系统在出现故障时,允许损失部分可用性,以保证系统基础运转仍然正常;

  • S(soft state):软状态,指允许系统中的数据存在中间状态,并且该中间状态不影响系统的可用性;

  • E(eventually consistent):最终一致性,指系统中的所有副本在经过一段时间的同步之后,最终总能够达到一致的状态;

BASE理论的约束比CAP更加松散且易于实现,对于NoSQL来说,它们全部都符合BASE理论,即舍弃强一致性而追求最终一致性。其实保证最终一致性的手段很多, 重量级的方案比如直接引入分布式事务,如2PC、3PC、TCC等,轻量级的方案可以在业务中自己实现,如重试+幂等性保证、状态机、重做日志等。