Append only和Reuse block之间的抉择

注:节选了作者关于AOF和Reuse block之间的一些理解,大家可以参考。

毫无疑问,正如每一种NoSQL都有其适用场景,这里每一种访问需求都有不同的答案,针对用户的访问需求做决定和测试产品是唯一正确的选择。

简单来说,antirez的观点就是:

  1. Append only btree不会出现数据不一致的情况。因为它是只追加的,没有重用文件中的失效块。因为在block I/O layer,内核会做一些IO上的调度,以致我们的IO请求会和我们预期的不一致。(FIXME)这一点我后面会开一篇文章详细讲解。
  2. Append only btree的过期数据清理会是很大的问题,很可能会出现compaction永远赶不上write,这样就会一直在做compaction。

关于这一点,我曾经在内部邮件里跟人探讨过,过期数据清理如何才能不影响系统性能。

最重要的两点:

  1. 数据文件分多文件。在这一点上除了Berkeley DB Java Edition(以下简称JE)我还没有见到哪个NOSQL产品是如此设计的。
  2. Btree的数据结构。这一点其实要略次,不如上一点重要。

下面就JE的compaction(官方称clean)操作进行讲解:

目前JE里面的clean操作即这里的compaction,后台clean线程会根据其记录的数据目录下每个文件的utilization(利用率)判断是否需要对该文件执行clean操作,默认的配置是5%,如果某个文件有效数据低于了5%,那么clean线程将会读取这个文件里面的有效数据,append到目录下的最后一个文件(这个操作是可以在内存中的,叫defer write),最后直接删除这个文件,整个流程是可以多线程并行的(每个线程对应当前的若干文件)。另外,最重要的是,因为b+tree的设计读取某个节点需要将其父节点load到内存(父节点维护了到子节点的指针及子节点的key),因此即使进行所有数据的clean,那么只需要其b+tree非叶节点在内存中,你只需要在父节点上删除指向该节点的指针即可,除了最后拷贝文件的那5%的有效数据(这些数据还很有可能在Cache里),基本不会存在任何的io操作(删除文件并不耗时)。以1亿数据量为例,假设单条记录是1kb,默认每个非叶子节点可以有128个子节点,也就是说只要你为JE分配4.5GB内存,那么你的B+tree所有索引(非叶子节点,100w个左右)都可以在内存中了,此时你做clean的话,其IO消耗几乎可以不计了。这一设计在JE中叫Lazy migration。

看到这里我想大家应该就能明白,对于append only file,为什么多文件的设计会更好,这也算是解决了去年我的海量数据存储之Key-Value存储简介一文中的伏笔。

而选择B+tree而不使用Hash的原因又多了一个-_-。

至于Reuse blocks为什么不好,下面给出几条数据:

SSD盘上读、写、擦除操作耗时依次是:

20 microseconds, 200 microseconds, 1500 microseconds

擦除操作是写操作的7倍多。也就是说在SSD上,我们重用块的代价远大于重写节点,这还没有考虑写入放大以及SSD寿命的因素,众所周知,SSD在随机写多的情况下性能损耗非常厉害。

结论,这里虽然append only胜出,但是并不是说reuse block不好,至少innodb的成功证明了它是正确的,而如此选择的前提是,数据如果用纯内存去装太不明智了,因为互联网数据访问是有热点的,在“内存是新的硬盘 硬盘是新的磁带“到来之前,SSD毫无疑问是这个过度时期的最佳选择。

原文地址:forchenyun.javaeye.com

anyShare据说看到好文章不转的人,服务器容易宕机!
          

无觅相关文章插件,快速提升流量

分类 理论原地 · tag