NoSQL生态系统——事务机制,行锁,LSM,缓存多次写操作,RWN

13.2.4 事务机制

NoSQL系统通常注重性能和扩展性,而非事务机制。 传统的SQL数据库的事务通常都是支持ACID的强事务机制。要保证数据的一致性,通常多个事务是不可能交叉执行的,这样就导致了可能一个很简单的操作需要等等一个复杂操作完成才能进行的情况。 对很多NoSQL系统来说,对性能的考虑远在ACID的保证之上。通常NoSQL系统仅提供行级别的原子性保证,也就是说同时对同一个Key下的数据进行的两个操作,在实际执行的时候是会串行的执行,保证了每一个Key-Value对不会被破坏。对绝大多数应用场景来说,这样的保证并不会引起多大的问题,但其换来的执行效率却是非常可观的。在NoSQL中,Redis在事务支持这方面上不太一样,它提供了一个MULTI命令用来将多个命令进行组合式的操作,通过一个WATCH命令提供操作隔离性。这和其它一些提供test-and-set这样的低层级的隔离机制类似。

13.2.5 Schema-free的存储

还有一个很多NoSQL都有的共同点,就是它通常并没有强制的数据结构约束。即使是在文档型存储或者列式存储上,也不会要求某一个数据列在每一行数据上都必须存在。这在非结构化数据的存储上更方便,同时也省去了修改表结构的代价。而这一机制对应用层的容错性要求可能会更高。还有一个问题,就是数据库的表结构可能会因为项目的多次迭代而变得混乱不堪

13.3 数据可靠性

13.3.1 单机可靠性

单机可靠性理解起来非常简单,它的定义是写操作不会由于机器重启或者断电而丢失。通常单机可靠性的保证是通过把数据写到磁盘来完成的,而这通常会造成磁盘IO成为整个系统的瓶颈。而事实上,即使你的程序每次都把数据写到了磁盘,实际上由于操作系统buffer层的存在,数据还是不会立刻被写到物理磁盘上,只有当你调用fsync这个系统调用的时候,操作系统才会尽可能的把数据写到磁盘。 一般的磁盘大概能进行每秒100-200次的随机访问,每秒30-100MB的顺序写入速度。而内存在这两方面的性能都有数量级上的提升。通过尽量减少随机写,取而代之的对每个磁盘设备进行顺序写,这样能够减少单机可靠性保证的代价。也就是说我们需要减少在两次fsync调用之间的写操作次数,而增加顺序写操作的数量。下面我们说一下一些在单机可靠性的保证下提高性能的方法。

控制fsync的调用频率

Memcached是一个纯内存的存储,由于其不进行磁盘上的持久化存储,从而换来了很高的性能。当然,在我们进行服务器重启或者服务器意外断电后,这些数据就全丢了。因此Memcached 是一个非常不错的缓存,但是做不了持久化存储。 Redis则提供了几种对fsync调用频率的控制方法。应用开发者可以配置Redis在每次更新操作后都执行一次fsync,这样会比较安全,当然也就比较慢。Redis也可以设置成N秒种调用一次fsync,这样性能会更好一点。但这样的后果就是一旦出现故障,最多可能导致N秒内的数据丢失

使用日志型的数据结构(就是LSM tree)

像B+ 树这样的一些数据结构,使得NoSQL系统能够快速的定位到磁盘上的数据,但是通常这些数据结构的更新操作是随机写操作,如果你在每次操作后再调用一次fsync,那就会造成频繁的磁盘随机访问了。为了避免产生这样的问题,像Cassandra、HBase、Redis和Riak都会把写操作顺序的写入到一个日志文件中。相对于存储系统中的其它数据结构,上面说到的日志文件可以频繁的进行fsync操作。这个日志文件记录了操作行为,可以用于在出现故障后恢复丢失那段时间的数据,这样就把随机写变成顺序写了。 虽然有的NoSQL系统,比如MongoDB,是直接在原数据上进行更新操作的,但也有许多NoSQL系统是采用了上面说到的日志策略。Cassandra和HBase借鉴了BigTable的做法,在数据结构上实现了一个日志型的查找树。Riak也使用了类似的方法实现了一个日志型的hash表(译者:也就是Riak的BitCask模型)。CouchDB对传统的B+树结构进行了修改,使得对树的更新可以使用顺序的追加写操作来实现(译者:这种B+树被称作append-only B-Tree)。这些方法的使用,使得存储系统的写操作承载力更高,但同时为了防止数据异构后膨胀得过大,需要定时进行一些合并操作。

通过合并写操作提高吞吐性能

Cassandra有一个机制,它会把一小段时间内的几个并发的写操作放在一起进行一次fsync调用。这种做法叫group commit,它导致的一个结果就是更新操作的返回时间可能会变长,因为一个更新操作需要等就近的几个更新操作一起进行提交。这样做的好处是能够提高写操作承载力。作为HBase底层数据支持的Hadoop 分布式文件系统HDFS,它最近的一些补丁也在实现一些顺序写和group commit的机制。

13.3.2 多机可靠性

一些NoSQL系统提供了多机可靠性的支持。 Redis采用了传统的主从数据同步的方式。所有在master上执行的操作,都会通过类似于操作日志的结构顺序地传递给slave上再执行一遍。如果master发生宕机等事故,slave可以继续执行完master传来的操作日志并且成为新的master。可能这中间会导致一些数据丢失,因为master同步操作到slave是非阻塞的,master并不知道操作是否已经同步线slave了。CouchDB 实现了一个类似的指向性的同步功能,它使得一个写操作可以同步到其它节点上。 MongoDB提供了一个叫Replica Sets的架构方制,这个架构策略使得每一个文档都会保存在组成Replica Sets的所有机器上。MongoDB提供了一些选项,让开发者可以确定一个写操作是否已经同步到了所有节点上,也可以在节点数据并不是最新的情况下执行一些操作。很多其它的分布式NoSQL存储都提供了类似的多机可靠性支持。由于HBase的底层存储是HDFS,它也就自然的获得了HDFS提供的多机可靠性保证。HDFS的多机可靠性保证是通过把每个写操作都同步到两个以上的节点来实现的。 Riak、Cassandra和Voldemort提供了一些更灵活的可配置策略。这三个系统提供一个可配置的参数N,代表每一个数据会被备份的份数,然后还可以配置一个参数W,代表每个写操作需要同步到多少能机器上才返回成功。当然W是小于N的(RWN机制)。 为了应对整个数据中心出现故障的情况,需要实现跨数据中心的多机备份功能。Cassandra、HBase和Voldemort都实现了一个机架位置可知的配置,这种配置方式使得整个分布式系统可以了解各个节点的地理位置分布情况。如果一个操作需要等待另外的数据中心的同步操作成功才返回给用户,那时间就太长了,所以通常跨数据中心的同步备份操作都是异步进行的。用户并不需要等待另一个数据中心同步的同步操作执行成功。

 

未完待续!

posted @ 2017-01-06 15:11  bonelee  阅读(912)  评论(0编辑  收藏  举报