B+ Tree的缺点
B+树最大的性能问题是会产生大量的随机IO,随着新数据的插入,叶子节点会慢慢分裂,逻辑上连续的叶子节点在物理上往往不连续,甚至分离的很远,但做范围查询时,会产生大量随机读IO。
对于大量的随机写也一样,新插入的数据在磁盘上的位置可能相隔很远,会产生大量的随机写IO。
相比B+ Tree,LSM-Tree可能会损失一部分读性能,但换来了巨大的写性能的提升。
LSM-Tree原理
Memtable
当一个Memtable被写满时,它将变为immutable的,后面进来的数据将写入一个新的Memtable。而后台线程将会将Immutable Memtable flush进一个SST文件,并在flush好后将该Memtable销毁
数据结构
可选择的数据结构
- SkipList (Default)
- HashLinkList
- HashSkipList
- Vector
Memtable默认采用跳表实现
而哈希跳表我之前没有接触过,结果搜索后发现是先对哈希值取模放入对应的桶中,再在每个哈希桶中维护跳表结构。
这样的话应该会提升随机单个查询的速度,而范围查询应该会变慢一点。
此外,根据官方文档,只有SkipList支持并发插入。
Flush
三种情况下会触发flush操作
- 当某一个Memtable的大小超出了
ColumnFamilyOptions::write_buffer_size
- 当所有列族的Memtable的总大小超出了
DBOptions::db_write_buffer_size
,或者DBOptions::write_buffer_manager
发出了flush的信号。这种情况下size最大的那个Memtable将被flush - WAL的大小超过了
DBOptions::max_total_wal_size
。这种情况下最老的Memtable将被flush,以便清空它相应的WAL中的部分。
Write Ahead Log
RocksDB的每次更新都会写入两个位置:内存中的memtable(稍后将flush到SST文件)和磁盘上的预写日志(WAL)。而当Memtable中的数据flush后,WAL中对应的数据将被删除
WAL被用作故障后恢复数据,它默认是开启的。也可以通过配置关闭它。
SST File Format
<beginning_of_file>
[data block 1]
[data block 2]
...
[data block N]
[meta block 1: filter block]
[meta block 2: index block]
[meta block 3: compression dictionary block]
[meta block 4: range deletion block]
[meta block 5: stats block]
...
[meta block K: future extended block] (More meta blocks may be added in the future)
[metaindex block]
[Footer] (fixed size; starts at file_size - sizeof(Footer))
<end_of_file>
其中Filter Meta Block使用布隆过滤器。在查询内容前先用布隆过滤器判断是否有可能存在,如果肯定不存在,就不需要在该文件内做多余的查询。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。