共计 2027 个字符,预计需要花费 6 分钟才能阅读完成。
前文提到,所有进入 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 是如何来实现的