rocksdb - 使用RocksDB通过拆分容器来支持key-key-value(RowKey->Containers)
问题描述
支持我有键/值,其中值是字符串的逻辑列表,我可以在其中附加字符串。为了避免将单个字符串项插入队列导致重写整个列表的情况,我将使用多个键值对来表示它。
Key -> metadata of the value such as length and subkey format
Key-l1 -> value of item 1 in list
Key-l2 -> value of item 2 in list
Key-ln -> the lastest value in the list
我将覆盖 RocksDB 中的键比较器,以便对 Key-ln 格式键的排序首先是对键部分进行排序,然后是对 ln 部分进行排序(即按 Key 分组和排序,在同一 Key 值内按 ln 排序)。这样,在初始批量插入和以后的 sst 压缩期间,所有列表项及其根键和元数据都在 sst 中组合在一起。
追加一个新的列表项变成(1)首先读取Key-metadata,得到当前列表大小为n;2) 插入具有新值的 Key-l(n+1)。通过删除 Key-ln 并更新元数据,删除列表项与 RocksDB 一样。为了确保一致性,(1)和(2)将在 RocksDB 事务中完成。
这个设计好像没问题?
现在,如果我想为整个键值(列表)添加 TTL 的另一个功能,我会在 RocksDB 中使用 TTL 支持。我的理解是 TTL 删除过期项目发生在压缩过程中。但是,这种压缩不是在事务下完成的。RocksDB 不知道 Key-metadata 和 Key-ln 条目是相关的。完全有可能存在一个时间窗口,其中 Key->metadata(root node) 被删除而 (Key-ln) 的子节点尚未删除(或相反的顺序)。如果在此时间窗口内,有人读取或更新列表,则会得到不一致的 Key-list。有什么补救办法吗?
谢谢
解决方案
您应该使用Merge Operator,它专为此类附加值用例而设计。您的设计是read-before-write
,它具有性能损失,一般情况下应尽可能避免:NoSQL 中的 read-before-write 是什么?.
Options options;
options.merge_operator.reset(new StringAppendOperator(','));
DB::Open(options, kDBPath, &db)
...
db->Merge(WriteOptions(), "key", "value1");
db->Merge(WriteOptions(), "key", "value2");
db_->Get(ReadOptions(), "key", &result); // return "value1,value2"
上面的示例使用了一个预定义的StringAppendOperator
,它只是在末尾附加新值。您可以定义自己的 MergeOperator 来自定义合并操作。
在后端,在读取路径上进行合并操作(并进行压缩以减少版本号),详情:Merge Operator Implementation。
推荐阅读
- sql - 连接两个表并在 oracle sql 中进行透视
- javascript - 使用多个或在续集中
- ant-design-pro - 如何在antd cascader子选项标签中添加图标
- excel - Excel 64 位中的 ODBC 连接失败错误
- html - 如何在右侧移动导航栏项目
- php - 如何从给定的 json 中仅获取 HotelDetails?
- ajax - 使用 ajax 结果创建一个 django url
- excel - 更新 '000s 工作簿链接的一部分时出现问题
- html - 带有溢出的 Firefox inline-flex 获得空格
- firebase - 如何一直等待 Vue 直到从 firebase 获取数据?