数据库大体分为以下几类,有关系型(事务型)的数据库,以oracle、mysql为代表,有keyvalue数据库,以redis和memcached db为代表,有文档型数据库如mongodb,有列式数据库以HBase,cassandra,dynamo为代表,还要其他的图形数据库、对象数据 库、xml数据库等。
有些数据库本身就是分布式的数据库设计理念,比如上面的列式数据库;有些本身是单节点的设计架构,如redis、mongodb、关系型数据库;
但是考虑到整个系统的可用性,这么内存型的数据库都有分布式部署的机制,如redis的主从复制,mongodb的Master-slave,replicaset,mysql和oracle的主从结构。
这里提到老生常谈的CAP原理,在分区的情况下,可用性和一致性只能保证一个,也就是在分布式的情况下,保障最终一致性(BASE)。
下面简单总结一下
1、数据分布的模式
a、主从复制
主从模式是最常用的一种模式,从机保存有主的全量数量,常用在主提供写,多个从提供读的场景。主从数据的一致性,可以实现为强一致,也可以实现为最终一致,具体看应用的具体要求(一致性和可用性的折中)。
基于弱一致性的场景中,考虑可用性的要求,采用异步的记录日志的方式,如mysql中的replication机制的binlog,oracle的archive log,mongodb中的oplog等。
b、sharding机制
当单个节点无法承载所有的数据量时,需要对数据进行切分,也就是sharding机制,数据的切分有很多种如concurrent hash,以及自定义的路由策略。
一致性hash,优点是数据节点的加入和退出,受影响的数据的范围比较小。要考虑加入节点和节点宕机时,数据的迁移;当然基于可用性的考虑,在数据切分的基础上,需要数据的多个备份。采用了Hinted Handoff的技术,用来保证在有节点故障后系统的写操作不受太大影响。为了数据的均匀分布,可以把每个物理节点虚拟成多个逻辑节点,以逻辑节点作为环上的节点。节点的健康探测,可以基于gossip,也可以基于zookeeper进行管理维护。dynamo和cassandra中数据的切分分布是利用一致性hash。
自定义路由策略,可以设定主节点对数据进行路由,可以基于表的数据规则,如日期,或者连续的范围分区;对于节点的迁入和迁出,需要路由节点自己维护,并且由主节点对数据进行迁移,节点健康状态由主节点(或者zookeeper)进行维护。HBase中的数据分布就是定义了一个META表,涵盖了key的范围所在分区,就是类似这种策略。
c、多主模式
多主模式在平时用的不多,且数据的一致以及冲突,数据的合并比较复杂,这里不做阐述
2、一致性的解决方案
a、强一致性:
R+W>N,建设有3个节点,每次读时,读2个节点并且数据一致;写时,写2个节点都成功才算写成功。这种是强一致性。
2PC,3PC 多个节点都成功时,才算成功,否则进行回滚操作。
PAXOS,类似于2PC,解决分布式系统如何就某个值(决议)达成一致,进行投票选举。是一种无主的节点的算法。分布式的协调服务zookeeper就实现了这个算法,保障一致性。mongodb中的集群方案replicaset也实现了类似的算法。
b、 弱一致性(最终一致):
由于分布式系统在数据同步时的网络延迟等等因素,无法保证副本数据和主节点时刻保持一致,当出现不一致的时,可以采用以下几种策略保证最终一致性
Gossip(Cassandra,Dynamo),是带冗余容错算法,也就是最终一致性的算法,无法保证某时刻所有节点数据一致,它是一个去中心化的部署方式,集群中每个节点维护一组状态,状态可以用key,value,外带一个版本号表示,版本大的比版本小的数据新,节点之间相互交流数据的版本信息,并更新数据,类似病毒式的传递,这样数据可以达到最终一致。Cassandra就是采取这种策略来进行数据的同步,并且维护节点的健康状态。
向量时钟(Dynamo),是一种数据不一致导致冲突的解决策略,系统采用乐观锁的策略,这样对同一个值进行操作时,就可能会出现多个版本,由向量时钟来解决一致性;每个元素是(更新值的节点,序列号),每当更新一个值时,都带上这些信息,从下图可见,D3和D4出现数据的冲突,那么在下次操作时,会由更新值的节点做冲突的解决。Dynamo采用的就是这种策略进行冲突的解决。
时间戳(Cassandra),每次更新节点时,都带上时间戳信息,冲突的解决以时间戳最晚的为准。以Cassandra为代表。
Merle tree(Cassandra,Dynamo),在每个节点上针对每个区间里的数据构造一棵Merkle Tree,这样,在两台节点进行数据比对时,从Merkle Tree的根节点开始进行比对,如果根节点一样,则表示两个副本目前是一致的,不再需要任何处理;如果不一样,则遍历Merkle Tree,定位到不一致的节点也非常快速,大大节省了比对时间以及数据的传输量。Dynamo和cassandra中的副本同步采用这种方案。