MemTable
MemTable是一个内存中的数据结构,在将数据刷新到SST文件之前保存数据。它同时提供读和写功能——新的写操作总是将数据插入到memtable中,读操作必须在从SST文件中读取之前查询memtable,因为memtable中的数据是较新的。 一旦memtable被填满,它就变成不可变的,并被一个新的memtable替换。后台线程将memtable的内容刷新到一个SST文件中,然后可以销毁memtable.
影响memtable行为的最重要选项是:
- memtable_factory: memtable的工厂对象。通过指定工厂对象,用户可以更改memtable的底层实现,并提供特定于实现的选项。
- write_buffer_size: 单个memtable的大小。
- db_write_buffer_size: 跨列族的memtables的总大小。这可以用来管理memtables使用的总内存。
- write_buffer_manager: 用户可以提供自己的写缓冲区管理器来控制整个memtable内存使用情况,而不是指定memtable的总大小。覆盖db_write_buffer_size。
- max_write_buffer_number: 内存中内存表在刷新到SST文件之前累积的最大数量。
memtable的默认实现基于skiplist。除了默认的memtable实现之外,用户还可以使用其他类型的memtable实现,例如HashLinkList、HashSkipList或Vector来加速一些查询。
Skiplist MemTable
基于skiplist的memtable在读写、随机访问和顺序扫描方面都提供了良好的性能。此外,它还提供了一些其他memtable实现目前不支持的其他有用特性,比如并发插入( https://github.com/facebook/rocksdb/wiki/MemTable#concurrent-insert )和带提示的插入 ( https://github.com/facebook/rocksdb/wiki/MemTable#insert-with-hint )。
HashSkiplist MemTable
顾名思义,HashSkipList在哈希表中组织数据,每个哈希桶都是一个跳转列表,而HashLinkList在哈希表中组织数据,每个哈希桶都是一个排序的单链表。 这两种类型都是为了在执行查询时减少比较次数而构建的。一个很好的用例是将它们与可表的SST格式结合起来,并将数据存储在RAMFS中。
当执行查找或插入key时,使用选项检索目标密钥的前缀。前缀提取器,用于查找散列桶。在散列桶中,所有的比较都是使用整个(内部)键来完成的,就像基于SkipList的memtable一样。
基于哈希的memtables的最大限制是,跨多个前缀进行扫描需要复制和排序,这非常慢,而且内存开销很大。
Flush
有三种情况可以触发memtable刷新:
1.写入后Memtable大小超过write_buffer_size。
2.所有列族的memtable总大小都超过db_write_buffer_size,或者write_buffer_manager表示刷新。在这种情况下,最大的memtable将被刷新。
3.总WAL文件大小超过max_total_wal_size。在这个场景中,包含最老数据的memtable将被刷新,以便清除包含来自这个memtable的数据的WAL文件。
因此,可以在memtable满之前刷新它。这是生成的SST文件可以小于相应memtable的原因之一。 压缩是使SST文件小于相应memtable的另一个因素,因为memtable中的数据是未压缩的。
Concurrent Insert
如果不支持对memtables的并发插入,则多个线程对RocksDB的并发写操作将依次应用于memtable。 默认情况下启用了并发memtable insert,可以通过allow_concurrent_memtable_write选项关闭它,不过只有基于skiplist的memtable支持该特性。
Insert with Hint
In-place Update
Comparison
MemTable 类型 | SkipList 跳表 | HashSkipList | HashLinkList | Vector 向量 |
---|---|---|---|---|
优化用例 | 一般 | 特定键前缀中的范围查询 | 范围查询位于特定的键前缀内,每个前缀只有少量行 | 随机写大量工作负载 |
索引类型 | 二分查找 | 哈希+二分查找 | 哈希+线性查找 | 线性查找 |
完全的支持订购全数据库扫描? | 自然 | 非常昂贵(复制和排序以创建临时的完全有序视图) | 非常昂贵(复制和排序以创建临时的完全有序视图) | 非常昂贵(复制和排序以创建临时的完全有序视图) |
内存开销 | 平均(每个条目有多个指针) | High(散列桶+非空桶的跳过列表元数据+每个条目有多个指针) | Lower (哈希桶+每个条目的指针) | Low低(向量末尾的预分配空间) |
MemTable刷新 | 快速与恒定的额外内存 | 速度慢,临时内存使用率高 | 速度慢,临时内存使用率高 | 慢与恒定的额外内存 |
并发插入 | 支持 | 不支持 | 不支持 | 不支持 |
插入与提示 | 支持(如果没有并发插入) | 不支持 | 不支持 | 不支持 |