分析levelDB的架构
levelDB的组件
levelDB由以下几个组件组成:MemTable
,Immutable MemTable
,WAL
,SSTable
,Manifest
,Current
,Compaction
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
是不存在键重叠现象的。