海量存储的一致性和高可用

关于数据存储中著名的CAP定理, 很多业界人士都给出了自己的解决方案. 美其名曰:”打败CAP定理”, 总结如下:

最终一致性(Cassandra的做法):

对于分布式数据系统:

  • N — 数据复制的份数
  • W — 更新数据是需要保证写完成的节点数
  • R — 读取数据的时候需要读取的节点数

如果W+R>N,写的节点和读的节点重叠,则是强一致性。例如对于典型的一主一备同步复制的关系型数据库,N=2,W=2,R=1,则不管读的是主库还是备库的数据,都是一致的。

如果W+R<=N,则是弱一致性。例如对于一主一备异步复制的关系型数据库,N=2,W=1,R=1,则如果读的是备库,就可能无法读取主库已经更新过的数据,所以是弱一致性。

对于分布式系统,为了保证高可用性,一般设置N>=3。不同的N,W,R组合,是在可用性和一致性之间取一个平衡,以适应不同的应用场景。

如果N=W,R=1,任何一个写节点失效,都会导致写失败,因此可用性会降低,但是由于数据分布的N个节点是同步写入的,因此可以保证强一致性。

如果N=R,W=1,只需要一个节点写入成功即可,写性能和可用性都比较高。但是读取其他节点的进程可能不能获取更新后的数据,因此是弱一致性。这种情况下,如果W<(N+1)/2,并且写入的节点不重叠的话,则会存在写冲突

Storm的作者的建议:

将实时数据和离线数据进行架构整合, 数据的一致性交由批处理的离线数据负责, Storm产生的实时数据则保证可用性架构图

相关Blog

关于NOSQL的CAP分类:

CAP分类图

关注一致性和可用性的 (CA)

这些数据库对于分区容忍性方面比较不感冒,主要采用复制(Replication)这种方式来保证数据的安全性,常见的CA系统有:

  1. 传统关系型数据库,比如Postgres和MySQL等(Relational) ;
  2. Vertica (Column-oriented) ;
  3. Aster Data (Relational) ;
  4. Greenplum (Relational) ;

关注一致性和分区容忍性的(CP)

这种系统将数据分布在多个网络分区的节点上,并保证这些数据的一致性,但是对于可用性的支持方面有问题,比如当集群出现问题的话,节点有可能因无法确保数据是一致性的而拒绝提供服务,主要的CP系统有:

  1. BigTable (Column-oriented) ;
  2. Hypertable (Column-oriented);
  3. HBase (Column-oriented) ;
  4. MongoDB (Document) ;
  5. Terrastore (Document) ;
  6. Redis (Key-value) ;
  7. Scalaris (Key-value) ;
  8. MemcacheDB (Key-value) ;
  9. Berkeley DB (Key-value) ;

关于可用性和分区容忍性的(AP)

这类系统主要以实现”最终一致性(Eventual Consistency)”来确保可用性和分区容忍性,AP的系统有:

  1. Dynamo (Key-value);
  2. Voldemort (Key-value) ;
  3. Tokyo Cabinet (Key-value) ;
  4. KAI (Key-value) ;
  5. Cassandra (Column-oriented) ;
  6. CouchDB (Document-oriented) ;
  7. SimpleDB (Document-oriented) ;
  8. Riak (Document-oriented) ;

关于2pc的一致性和脑裂问题:

A prepare --> B commit --> A commit 

这是最原始的二阶段提交, 但是如果B的反馈未知, 那么整个集群则处于危险状况

  1. 一致性上就出现了问题,无反馈的情况下,无法区分成功还是失败了,于是最安全和保险的方式,就是等着。。。没错,你没看错,就是死等。等到B给个反馈。。。这种在可用性上基本上是0分了。。无论你有多少机器,死等总不是个办法

  2. A得不到B的反馈,又为了保证自己的可用性,唯一的选择就只好像【P A ->C B(b机器挂掉), 这里面所提到的方法一样:等待一段时间,超时以后,认为B机器挂掉了。于是自己继续接收新的请求,而不再尝试同步给B。又因为可用性指标是如此重要,所以这基本成为了在这种情况下的必然选择,然而,这个选择会带来更大的问题,左脑和右脑被分开了!

碰到问题,就要去解决,所以,针对一致性问题上的那个“死等”的萌呆属性,有人提出了三段提交协议,使用增加的一段提交来减少这种死等的情况。不过3PC基本上没有人在用,因为有其他协议可以做到更多的特性的同时又解决了死等的问题,所以3pc我们在这里就不表了。3pc是无法解决脑裂问题的,所以更多的人把3pc当做发展过程中的一颗路旁的小石头。。

而针对脑裂,最简单的解决问题的方法,就是引入第三视点,observer。

既然两个人之间,直接通过网络无法区分出对方是不是挂掉了,那么,放另外一台机器在第三个机房,如果真的碰到无响应的时候,就去问问observer:对方活着没有啊?就可以防止脑裂问题了。但这种方法是无法解决一致性问题中的死等问题的。。。

所以,最容易想到的方式就是,3pc+observer,完美解决双机一致性和安全性问题。

参考资料: http://qing.blog.sina.com.cn/1765738567/693f084733002ibn.html http://f.dataguru.cn/thread-140985-1-1.html http://blog.csdn.net/cutesource/article/details/5621725


推荐一篇必看的NOSQL比较 http://kkovacs.eu/cassandra-vs-mongodb-vs-couchdb-vs-redis