ToplingDB是 RocksDB 的一个增强版分支,我来贡献一个知识点:
控制内存使用的 WriteBufferManager
在你使用了很多个 ColumnFamily 的情况下,可以使用 WriteBufferManager 对 MemTable 的内存总量进行约束。
我们在开发 Todis 的时候也有类似需求,不过借助于 ToplingDB 的 SidePlugin 体系,可以让这一切变得更加轻松。
RocksDB 中使用 Column Family 对数据库进行逻辑分区,每一个 KeyValue 属于一个特定的 Column Family 。同一个 DB 下不同的 Column Family 之间只共享 WAL 文件, MemTable 和 SST 文件都是彼此独立的。
以 Todis 为例,Todis 进程会打开 5 个 DB ,共使用 9 个Column Family 。也就是说 Todis 运行时内存中会有 9 组独立的 Memtable ,总的内存使用量可能大幅增加。虽然可以设置 ColumnFamilyOptions .write_buffer_size 来限制单个 Memtable 的大小,但我们更需要的是限制总的 Memtable 的内存使用量。如果只设置单个 Memtable 的内存上限,很容易陷入要么有大量内存闲置浪费,要么所有的 Memtable 都在写入数据而导致 OOM 的境地。
这就是 WriteBufferManager 要解决的问题,使用原版 RocksDB,大致就像这个样子:
Options options1 , options2;
DB *db1 , *db2;
auto wbm = std::make_shared<WriteBufferManager>(128u << 20);
options1.write_buffer_manager = wbm;
options2.write_buffer_manager = wbm;
DB::Open(options1, DBPath1, &db1);
DB::Open(options2, DBPath2, &db2);
在这个片段中,我们将 options1 和 options2 的 write_buffer_manager 选项指向一个内存用量上限为 128 MB 的 WriteBufferManager 实例 wbm 。当我们打开 DB 时, db1 和 db2 下的所有 Column Family 均会受到 wbm 的约束, MemTable 占用的总内存不会超过 wbm 的设定值 128 MB 。
除此之外, WriteBufferManager 还支持指定的 Block Cache 消耗被 MemTable 使用的内存,这可以让 RocksDB 仅通过一个设置来限定 Memtable 和 Block Cache 的总内存上限。
在 ToplingDB 的 SidePlugin 中使用 WriteBufferManager
WriteBufferManager 是 RocksDB 自身的组件,所以,我们在 ToplingDB 的 SidePlugin 体系中内置了对它的支持,这样就可以通过 json/yaml 配置来使用它。使用方法也与在代码中使用 WriteBufferManager 类似:
创建一个 WriteBufferManager 实例
在配置文件中增加下列片段,我们就创建了一个名为 wbm_example 的 WriteBufferManager 实例,它的内存限制用量为 128MB 。
"WriteBufferManager" : {
"wbm_example": {
"class": "WriteBufferManager",
"params": {
"buffer_size": "128M"
}
}
}
将 WriteBufferManager 关联到 DBOptions
"databases": {
"db_mcf": {
"method": "DB::Open",
"params": {
"db_options": {
"create_if_missing": true,
"write_buffer_manager": "${wbm_example}"
},
"column_families":
{
...
更多的用法,可以参考 Todis 示例配置文件中关于 WriteBufferManager 和 database 中对 db_options 的设置。