前文提到,所有进入RocksDB的数据,会先进入内存,再flush进disk。本文,我们会学习到,RocksDB 如果管理和存储内存中的数据。
图1 RocksDB 架构图(source:https://www.slideshare.net/me...
RocksDB有三种基本文件格式是 Memtable/SST file/Log file。Memtable 是一种内存文件数据系统,新写数据会被写进 Memtable,部分请求内容会被写进 Log file。Log file 是一种有利于顺序写的文件系统。Memtable 的内存空间被填满之后,会有一部分老数据被转移到 SST file 里面,这些数据对应的 Log file 里的 log 就会被安全删除。SST file 中的内容是有序的。
MemTable
MemTable是一个内存数据结构,他保存了落盘到SST文件前的数据。他同时服务于读和写——新的写入总是将数据插入到memtable,读取在查询SST文件前总是要查询memtable,因为memtable里面的数据总是更新的。一旦一个memtable被写满,他会变成不可修改的,并被一个新的memtable替换。一个后台线程会把这个memtable的内容落盘到一个SST文件,然后这个memtable就可以被销毁了。并且在flush的过程中,会完成数据的压缩
RocksDB默认实现方式是SkipList,适用于范围查询和插入,但是如果是其他场景,RocksDB也提供了另外两种实现方式。具体区别可参考https://github.com/facebook/rocksdb/wiki/MemTable
- a vector memtable:适用于批量载入过程,每次新增元素都会追加到之前的元素后,当MemTable的数据被刷入L0时,数据会按之前的顺利刷入SST file
- a prefix-hash memtable:适用于带有指定前缀的查询,插入和scan
Immutable Memtable
所有的写操作都是在memtable进行,当memtable空间不足时,会创建一块新的memtable来继续接收写操作,原先的内存将被标识为只读模式,等待被刷入sst。在任何时候,一个CF中,只存在一块active memtable和0+块immutable memtable。刷入时机有以下三个条件来确定:
- write_buffer_size 设置一块memtable的容量,一旦写满,就标记为只读,然后创建一块新的。
- max_write_buffer_number 设置memtable的最大存在数(active 和 immutable 共享),一旦active memtable被写满了,并且memtable的数量大于max_write_buffer_number,此时会阻塞写操作。当flush操作比写入慢的时候,会发生这种情况
- min_write_buffer_number_to_merge 设置刷入sst之前,最小可合并的memtable数,例如,如果设置2,只有当 immutable memtable数量达到2的时候,会被刷入sst,数量为1的时候,则永远不会被刷入。
由于每次Get()都需要线性查询每个memtable,所以,如果这个值太高,会影响写的性能
例如:
write\_buffer\_size = 512MB;
max\_write\_buffer\_number = 5;
min\_write\_buffer\_number\_to\_merge = 2;
当写入速达到 16MB/s,每32s会创建一块新的memtable,每64s会有2块memtable合并,并刷入sst 。Depending on the working set size,每一刷在512MB 到 1GB之间。为了防止刷入操作影响写性能,内存使用上限是5*512MB = 2.5GB。到达上限后,所有的写请求将会被阻塞。
WAL(Write-ahead Log)
每次数据被更新时,会同时写入内存表和WAL,WAL可用于发生故障后,恢复内存的数据。
在以下情况下会创建一个WAL:
- 新打开一个DB
- flush了一个column family。一个WAL文件只有当所有的列族数据都已经flush到SST file之后才会被删除,或者说,所有的WAL中数据都持久化到SST file之后,才会被删除。归档的WAL文件会move到一个单独的目录,后续从磁盘中删除。
- 每条都刷盘 - 安全系数最高,只要写成功,数据就不会丢,性能最低
- 批量刷盘 - 最多丢失配置项大小的数据
- 完全交给操作系统(Defualt),另外在存在多个column family,并发生Memtable flush时,rocksDB会主动刷盘 - 丢失的数据比上面两种方式更多
处于简介,此处没有对两者的内部实现,以及生命周期做详细描述,如果有感兴趣的同学,建议直接看完官方文档,看源码。下文,我们会学习SST的compaction是如何来实现的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。