概述¶
RocksDB 中的每个更新操作都会写到两个地方:1) 一个内存数据结构,名为 memtable(后面会被刷盘到 SST 文件) 2) 写到磁盘上的 WAL 日志。在出现崩溃的时候,WAL 日志可以用于完整的恢复 memtable 中的数据,以保证数据库能恢复到原来的状态。在默认配置的情况下,RocksDB 通过在每次写操作后对 WAL 调用 fflush 来保证一致性。
WAL 的生命周期¶
我们用一个例子来说明一个 WAL 的生命周期。一个 RocksDB 的 db 实例创建了两个列族:"new_cf" 和 "default"。一旦 db 被打开,一个新的 WAL 会在磁盘上被创建,以保证写持久性。
DB* db;
std::vector<ColumnFamilyDescriptor> column_families;
column_families.push_back(ColumnFamilyDescriptor(
kDefaultColumnFamilyName, ColumnFamilyOptions()));
column_families.push_back(ColumnFamilyDescriptor(
"new_cf", ColumnFamilyOptions()));
std::vector<ColumnFamilyHandle*> handles;
s = DB::Open(DBOptions(), kDBPath, column_families, &handles, &db);
往列族中加入一些数据:
db->Put(WriteOptions(), handles[1], Slice("key1"), Slice("value1"));
db->Put(WriteOptions(), handles[0], Slice("key2"), Slice("value2"));
db->Put(WriteOptions(), handles[1], Slice("key3"), Slice("value3"));
db->Put(WriteOptions(), handles[0], Slice("key4"), Slice("value4"));
这是,WAL 需要记录所有的写操作。WAL 会保持打开,并不断跟踪后续的写操作,直到他的大小到达 DBOptions::max_total_wal_size
如果用户决定把列族 "new_cf" 的数据落盘,以下的事情会发生
- new_cf 的数据 (key1 和 key3) 会被落盘到一个新的 SST 文件
- 一个新的 WAL 会被创建,现在后续的写操作都会写到新的 WAL 了
- 旧的 WAL 不再接受新的写入,但是删除操作会被延后
db->Flush(FlushOptions(), handles[1]);
// key5 与 key6 会出现在新的 WAL中
db->Put(WriteOptions(), handles[1], Slice("key5"), Slice("value5"));
db->Put(WriteOptions(), handles[0], Slice("key6"), Slice("value6"));
这时,会有两个 WAL 文件,老的保存有从 key1 到 key4 的内容,新的保存 key5 和 key6.因为老的还有线上数据,就是 "defalut" 列族的,他还不能被删除。只有当用户最后决定把 "default" 列族的数据落盘,老的 WAL 才能被归档,然后自动从磁盘上删除。
db->Flush(FlushOptions(), handles[0]);
// 老的WAL文件会一步步地被归档,然后删除。
总的来说一个 WAL 文件会在以下时机被创建
- DB 打开的时候
- 一个列族落盘数据的时候
一个 WAL 会在他持有的所有列族的数据的最大请求序列号落盘后被删除(或者归档,如果允许归档),换句话说,所有的 WAL 里的数据都被固定到 SST 文件。归档 WAL 会被移到一个独立的位置,然后再从存储设备上清除。实际的删除动作可能会因为拷贝的原因被延后,参考食物日志迭代器章节。
WAl 配置¶
下面这些配置可以在 options.h 中找到
DBOptions::wal_dir¶
DBOptions::wal_dir 用于设置 RocksDB 存储 WAL 文件的目录,这允许用户把 WAL 和实际数据分开存储
DBOptions::WAL_ttl_seconds, DBOptions::WAL_size_limit_MB¶
这两个选项影响 WAL 文件删除的时间。非 0 参数表示时间和硬盘空间的阈值,超过这个阀值,会触发删除归档的 WAL 文件。参考源文件以了解更多内容
DBOptions::max_total_wal_size¶
如果希望限制 WAL 的大小,RocksDB 使用 DBOptions::max_total_wal_size 作为列族落盘的触发器。一旦 WAL 超过这个大小,RocksDB 会开始强制列族落盘,以保证删除最老的 WAL 文件。这个配置在列族以不固定频率更新的时候非常有用。如果没有大小限制,如果这个 WAL 中有一些非常低频更新的列族的数据没有落盘,用户可能会需要保存非常老的 WAL 文件。
DBOptions::avoid_flush_during_recovery¶
选项名已经说明了他的用途(恢复过程中避免落盘)
DBOptions::manual_wal_flush¶
DBOptions::manual_wal_flush 决定 WAL 是每次写操作之后自动 flush 还是纯人工 flush(用户必须调用 FlushWAL 来触发一个 WAL flush)
DBOptions::wal_filter¶
通过 DBOptions::wal_filter,用户可以提供一个在恢复过程中处理 WAL 文件时被调用的 filter 对象。注意:ROCKSDB_LITE 模式不支持该选项。
WriteOptions::disableWAL¶
如果用户依赖于其他写日志方式,或者不担心数据丢失,WriteOptions::disableWAL 就非常有用了
WAL 过滤器¶
事务日志迭代器¶
事务日志迭代器提供一种方法,用来在 RocksDB 实例间复制数据。一旦一个 WAL 因为列族被落盘而被归档,WAL 不会马上被删掉。这是为了允许事务日志迭代器可以继续读取 WAL 文件,再发送给从节点。