WAL 性能

Non-Sync模式

当WriteOptions.sync = false(默认值),WAL写操作不同步到磁盘。除非操作系统认为它必须刷新数据(例如太多脏页面),否则用户不需要等待任何I/O来写。

想要通过写入OS页面缓存来减少CPU延迟的用户可以选择选项。manual_wal_flush = true。 使用这个选项,WAL写甚至不会被刷新到文件系统页面缓存,而是保存在RocksDB中。 用户需要调用DB::FlushWAL()来将缓冲的条目保存到文件系统中。

用户可以调用DB::SyncWAL()来强制fsync WAL文件。 该函数不会阻塞在其他线程中执行的写操作。

在这个mod中,WAL写是不安全的。

Sync 模式

当WriteOptions.sync = true,在返回给用户之前对WAL文件进行fsync。

Group Commit 组提交

与大多数其他依赖日志的系统一样,RocksDB支持group commit来提高WAL的写吞吐量以及写放大。 RocksDB的组提交是用一种简单的方式实现的:当不同的线程同时向相同的DB写入时,所有符合组合条件的未完成的写操作都将组合在一起, 并使用一个fsync向WAL写入一次。通过这种方式,相同数量的I/Os可以完成更多的写操作。

具有不同写选项的写可能会取消组合它们的资格。组的最大大小为1MB。 RocksDB不会通过主动延迟写操作来增加批处理大小。

每次写I/Os的数量

如果Options.recycle_log_file_num = false(默认值)。RocksDB总是为新的WAL段创建新文件。 每次WAL写都将同时更改数据和文件大小,因此每个fsync将生成至少两个I/Os,一个用于数据,一个用于元数据。 注意,RocksDB调用fallocate()来为文件预留足够的空间,但它不会阻止fsync中的元数据I/O。

Options.recycle_log_file_num = true 将保存一个WAL文件池,并尝试重用它们。 在对现有日志文件进行写入时,使用大小为0的随机写入。在写到达文件末尾之前,文件大小不会改变,因此可以避免元数据的I/O(也取决于文件系统挂载选项)。 假设大多数WAL文件都具有类似的大小,元数据所需的I/O将是最小的。

写放大

注意,对于相同的用例,同步WAL可以引入非平凡的写放大。当写操作很小时,因为可能需要更新完整的块/页,所以即使写操作非常小,我们也可能会有两个4KB的写操作(一个用于数据,一个用于元数据)。 如果写入仅为40字节,则更新8KB,写入放大为8KB /40字节~= 200。它很容易比LSM-tree的写入放大更大。