0%

levelDB源码剖析(2)--分析levelDB的架构

分析levelDB的架构


levelDB的组件

levelDB由以下几个组件组成:MemTableImmutable MemTableWALSSTableManifestCurrentCompaction

MemTable:这个组件是操作的入口,是常驻内存的树,所有的写入操作都将被直接写入到此树中。另外这棵树是有序的,可以对其进行快速查找和遍历,也支持数据库的操作。

它本身就可以看成是一个数据库,相当于levelDB内置的redis。

当其占用空间到达一个阈值时,就转换成一个Immutable MemTable供后续合并,同时生成一个新的MemTable来继续执行下去。

Immutable MemTable:这个组件是内存与磁盘的交互组件。它与MemTable完全一样,仅仅在于其是只读结构。

当生成Immutable MemTable后,后台线程会将其创建出一个SSTable,并归并到磁盘中。

WAL:即write ahead log,在写入到数据库之前,先写入到日志文件。

这样做的目的是为了不丢失数据,由于MemTable位于内存中,写入一些数据后,其不能立刻同步到磁盘中,如果突然掉电,这样写入的数据就丢失了。而WAL位于磁盘中,不过由于日志结构是顺序写,因此其写入效率也是很高的。

每次数据库重启时都需要读取日志并进行恢复,如果日志结构太大,启动数据库的速度就会很慢。

SSTable:即Sorted String Table。这是比较重要的结构,虽然数据库的读写是基于MemTable的,但是其位于内存中,内存不是无限大的,需要被持久化到磁盘中。当创建出Immutable MemTable后,就会对其创建出一个SSTable来保存数据到磁盘上。

其有序体现在键是有序的,同时各级的SSTable文件之间也是有序的,即键不重叠。这样做的目的是为了保持良好的读速度。由于levelDB不需要更新磁盘数据结构,因此不需要使用B+树。当数据存储在磁盘上键有序,这样就可以使用高效的二分查找;而键不重叠则避免二分查找读多个磁盘块。

同时,将MemTable写入到磁盘上的SSTable后就可以释放掉这部分的日志空间,减少下次启动时的恢复速度。

但是当SSTable数目变多时,可能会导致键的范围出现重叠,这时候可以进行合并,将多个小的SSTable合并成一个大的,由于SSTable是有序的,其合并速度也是十分的快。

Manifest:LevelDB中有版本Version的概念,一个版本Version主要记录了每一层Level中所有文件的元数据。随着Compaction的进行,元数据会改变,所以每次还需要将改变的元数据写到MANIFEST中。

Current:本文件指向当前的Manifest文件,由于可能存在多个Manifest文件,Current文件指向我们当前需要用到的Manifest文件。

Compaction:作用是将多个小的SSTable合并成一个大的SSTable。这样可以解决查找的效率问题。

每个大的SSTable是键有序的,可以将其再次分成多个小的键不重叠的SSTable,这样每次合并时只需要合并小的SSTable即可,而不需要去读取一个很大的SSTable

另外,由于level-0是直接由内存写入的,其多个SSTable可能存在键重叠现象,但是更高层的level是不存在键重叠现象的。