常见的LeveDB提供了内部同步机制,这样就允许多个线程并行地访问数据存储。在内部,写是按照FIFO顺序进行的:处于FIFO最先位置的写线程是唯一一个可以写入数据库的线程,而且所有正在排队的其他线程必须等待。每次写都向磁盘的备份日志和内存的备份“内存表”里插入数据。这个日志是只增加的文件,他可以为崩溃恢复提供持久性支持,而这个内存表是已经排序的跳跃表,它能够使读线程快速地查找存储在日志里的数据。在向FIFO里的下一个写线程发送信号之前,当前写线程必须向日志和内存表里写入数据。
为了克服排队所造成的影响,常见的LevelDB分批写FIFO最开始部分所包含的数据,在一个分批处理里有许多写线程在写入数据。这样的分批处理提高了性能,尤其是提高了同步写的性能,不过从根本上来说,没有更改顺序写这个特性。还可能花费更多资源,因为做分批处理的线程必须读,并且可能拷贝其他线程写入的数据。只要FIFO的最先位置的线程正在做任何真正的写工作的话,内核就阻塞其他写线程,以等待最先位置的写线程所发送信号。
HyperLeveDB并行性
HyperLevelDB改进了写线程的并发性:允许多个写线程独立地插入自身要写的内容到日志和内存表里,同时仅仅为了维护写的顺序而使用同步机制。为了了解HyperLevelDB是如何做这些工作的,理解LevelDB里读和写交互的方式就特别重要。
在LevelDB内部,LevelDB为每次写都指定了一个由不断增长的计数器产生的唯一序号。这些序号使得读线程能够及时地从某个特定的位置读取数据,序号适时地标注这个位置,而且忽略了任何在这个序号之后所发生的写。LevelDB快照捕捉在创建快照那个时刻的最后一个序号,使得在不用查看任何后续的写内容的情况下不断地替换快照或者读取数据。任何不能在快照上执行的读都隐含地使用了最新的序号。序号是HyperLeveDB并行优化的关键,因为它们给出控制读线程可看到的数据范围的一种方法。改进了压缩
LevelDB这个名字源于它使用了层级性的存储结构。数据是存储在每个层级里的,每个层级比下面层级存储更多数据。在每个层级内部,数据是排序的,并且存储在称作排序字符串表或者SST的文件里,这儿每个排序字符串表也进行了排序,并且排序字符串表是非重叠的,因此每个关键字最多存储在一个字符串表里。写的内容将合并这棵层级树的底部,然后名字为压缩的进程将透过层级把数据上移,同时在每个层级内部保持排序。
LevelDB内部使用的增量压缩是在不压缩和全压缩两个压缩极端之间权衡的结果。如果没有任何压缩的话,那么写入系统的数据就是无序的,执行关键字查找就需要线性地访问所有数据。另外压缩也可以采用另一个极端,在这种情况下排序所有的一切,这时产生不断增大的排序字符串表,并且每次压缩都重新把全部数据写入磁盘。LevelDB里的压缩确保数据是排序的,同时提高读的效率,不过执行增量压缩可以限制压缩写入数据的数量。降低写放大的压缩器
HyperLevelDB更改了压缩算法,明显地选择在两个级别直接产生最小写放大的一组字符串排序表。一个后台压缩线程监控每个层级 的大小,并且对最适合压缩的一组字符串排序表进行压缩。第二个后台线程在第一个线程无法承受更多负载的时候触发,它执行 全局优化以选择可降低写放大的压缩目标,而且并不关心每个层级的大小。典型的情况是,第二个线程将在不做任何写放大的情况下 从下层级移动文件。对上面的层级来说,第二个线程抢先压缩数据,这经常足以使得高层级的大小比第一个线程所使用的限制大小的启发法所得的结果要小,同时确保第一个后台线程不和高级别的压缩紧密相连。
评论删除后,数据将无法恢复
评论(1)