ToplingDB CSPP MemTable

用户手册

cspp-memtable 在 SidePlugin 中配置,类名是 cspp,配置参数:

配置样例:使用 yaml

MemTableRepFactory:
  cspp:
    class: cspp
    params:
      mem_cap: 2G
      use_vm: false
      token_use_idle: true
  skiplist:
    class: SkipList
    params:
      lookahead: 0

在 yaml 中定义好 cspp 对象之后,这样引用该 cspp memtable

配置样例:使用 json

"MemTableRepFactory": {
   "cspp": {
      "class": "cspp",
      "params": {
         "mem_cap": "2G",
         "use_vm": false,
         "token_use_idle": true
      }
   },
   "skiplist": {
      "class": "SkipList",
      "params": {
         "lookahead": 0
      }
   }
}

在 json 中定义好 cspp 对象之后,这样引用该 cspp memtable

memtablerep_bench

ToplingDB 在 RocksDB 的 memtablerep_bench 中加入了 cspp,以下脚本对比 skiplist 和 cspp(linux 下必须保证设置了足够的 vm.nr_hugepages

make DEBUG_LEVEL=0 memtablerep_bench -j`nproc`
./memtablerep_bench -benchmarks=fillrandom,readrandom,readwrite \
  -memtablerep=skiplist -huge_page_tlb_size=2097152 \
  -write_buffer_size=536870912 -item_size=0 -num_operations=10000000
./memtablerep_bench -benchmarks=fillrandom,readrandom,readwrite \
  -memtablerep='cspp:{"mem_cap":"16G","use_hugepage":true}' \
  -write_buffer_size=536870912 -item_size=0 -num_operations=10000000
  • 注意:-item_size=0 表示将 value 的长度设为 0,从而去除 memcpy value 的影响
  • 注意:测试结果中最有参考价值的指标是 write us/op 和 read us/op
  • 注意:测试结果表现出的性能差异包含了调用链开销,如果去除调用链开销,性能的差异会更大
    • 调用链开销是固定的,在 skiplist 中占比不大,但在 cspp 中占比就很大了(~40%)
    • 在 DB 中使用 CSPP,调用链开销更大,即便如此,最终的加速比也是非常显著

从问题到解决方案,我是怎么思考的:

(一)问题背景

在 MyRocks 的一个场景,MyRocks(RocksDB+MySQL) 的表现远不如预期,写入速度甚至只有 InnoDB 的 70%。这是我们万万不能接受的一个结果,经过仔细排查,我们发现,SkipList 相关的时间开销(主要是 Comparator 耗时)占了 60% 以上!

在这个场景中,数据条目数量非常大(20 多亿条),但表的结构很简单,类似这样:

CREATE TABLE Counting(
    name     varchar(100) PRIMARY KEY, # 实际平均长度约 30 字节
    count    INT(10)
);

每天会进行一次批量数据更新,大约更新 1亿条 数据,这个更新过程,InnoDB 需要 12分钟,MyRocks 需要 17分钟。

在 MyRocks 中,Counting 表对应到存储引擎上:name 字段就是 key,count 字段是 value,对于一般的场景,value 尺寸是远大于 key 的,但在这个场景中,key 的尺寸却远大于 value,一下就命中了 MyRocks 的软肋……

(二)RocksDB 的 MemTable

架构上,RocksDB MemTable 的设计目标是可插拔的不同实现的,在具体实现上,RocksDB 使用 SkipList 作为默认的 MemTable,其最大的优点是可以并发插入。

然而,RocksDB MemTable 的架构设计实际上有诸多的问题:

1. MemTable 不允许插入失败

每个 MemTable 有内存上限(write_buffer_size),是否达到内存上限,通过一种很猥琐的方式来判定:

    • MemTable 需要自己实现一个虚函数,用来报告自己的内存用量
    • 管理层根据 MemTable 报告的内存用量,决定是否冻结当前 MemTable 并创建新的 MemTable
    • 如此,引发了一个很严重的问题:#4056
    • 这个缺陷非常致命,直接导致内存用量无法精确控制,严重阻碍优化方案的实现;更致命的是相关的代码错综复杂,几乎无法修改,我们进行了大量的尝试,最终还是只能放弃,退回到次优化的实现
这个问题我们现在已经解决(规避)了,仅 保留地址空间,但并不实际分配:使用 VirtualAlloc/mmap 分配足够的内存地址空间(例如 16G),这些地址空间只有用到时才会真正地分配物理内存,从而在事实上不会突破 MemTable 的内存限制

2. MemTable 限死了 KeyValue 的编码方式

都由带 var int 前缀的方式编码,这又带来了至少两个严重的问题:
(1) var int 解码需要 CPU 时间,并且 key value 都无法自然对齐(对齐到 4 字节或 8 字节)
(2) 新的 MemTable 无法使用别的存储方式,例如基于 Trie 树的 MemTable 不需要保存 Key,而是在搜索/扫描的过程中重建 Key

    • 这个缺陷可以通过重构来解决,我们曾向 RocksDB 提交过相关的 Pull Request 但未被接受(这类问题是 ToplingDB 必须独立存在的一个重要原因)

3. 工厂机制形同摆设

新的 MemTable 不能无缝 plugin,这个缺陷我们也曾经提交过相关的 Pull Request(也未被接受)

经过这些重构,其结果就是 ToplingDB 的通用 MemTable 接口,这个接口,放进 SidePlugin 体系,就实现了 MemTable 的无缝插件化。

架构上的改进,如果没有高效的实现来验证,总是缺乏一些说服力,我们经过不懈的努力,在算法层面获得了 8 倍以上的性能提升,同时 MemTable 的内存用量还大大降低。当然,这个提升,在整个系统层面会被其它部分拖后腿,最终效果是:在 MyRocks 中的一些场景下,我们可以获得 70% 以上的性能提升。

(三)从头实现了 CSPP

基于 CSPP,我们实现了 CSPPMemTab,设计上,CSPP 是 DFA 体系的一员,和 RocksDB 完全独立,也就是说,CSPPMemTab 把 CSPP 作为一个基本构造块,CSPPMemTab 是 CSPP 到 RocksDB MemTable 的适配层。

(四)Comparator 问题

作为一个 Trie,它里面的 Key 对外部观察者而言只能是字典序,自然,CSPPMemTab 也只能支持 BytewiseComparator(和 Reverse Bytewise)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
select * from (select t1.[id] as t1_id,t1.[requestId] as t1_requestId,t1.[htqsrq] as t1_htqsrq,t1.[htjzrq] as t1_htjzrq,t1.[htbh] as t1_htbh,t1.[gf] as t1_gf,t1.[xf] as t1_xf,t1.[rq] as t1_rq,t1.[fkfs] as t1_fkfs,t1.[formmodeid] as t1_formmodeid,t1.[modedatacreater] as t1_modedatacreater,t1.[modedatacreatertype] as t1_modedatacreatertype,t1.[modedatacreatedate] as t1_modedatacreatedate,t1.[modedatacreatetime] as t1_modedatacreatetime,t1.[modedatamodifier] as t1_modedatamodifier,t1.[modedatamodifydatetime] as t1_modedatamodifydatetime,t1.[form_biz_id] as t1_form_biz_id,t1.[MODEUUID] as t1_MODEUUID,t1.[htfj] as t1_htfj,t1.[zje] as t1_zje,t1.[ds] as t1_ds,t1.[zjedx] as t1_zjedx,t1.[cspp] as t1_cspp,t1.[yfk] as t1_yfk,t1.[gxid] as t1_gxid,t1.[bz] as t1_bz,t1.[gfqymc] as t1_gfqymc,t1.[gfjc] as t1_gfjc,t1.[bh] as t1_bh,t1.[jylx] as t1_jylx,t1.[cght] as t1_cght,t1.[yf] as t1_yf,t1.[yfk1] as t1_yfk1,t1.[yf11] as t1_yf11,t1.[nf] as t1_nf,t1.[rksj] as t1_rksj,t1.[cclx] as t1_cclx,t1.[cgbt] as t1_cgbt,t1.[yfk2] as t1_yfk2,t1.[sywf] as t1_sywf,t1.[yfbl] as t1_yfbl,t1.[fhbl] as t1_fhbl,t1.[yfh] as t1_yfh,t1.[sykf] as t1_sykf,t1.[hzsdlqys] as t1_hzsdlqys,t1.[sys_workflowid] as t1_sys_workflowid,t1.[cgqzyz] as t1_cgqzyz,t1.[htwjpdf] as t1_htwjpdf,t1.[cghtlc] as t1_cghtlc,t1.[htzt] as t1_htzt,t1.[qzfs] as t1_qzfs,t1.[htwjtp] as t1_htwjtp,t1.[cgqzlc] as t1_cgqzlc,t1.[sjfk] as t1_sjfk,t1.[ydkds] as t1_ydkds,t1.[chpt] as t1_chpt,t1.[lxdhchr] as t1_lxdhchr,t1.[gxsjkx] as t1_gxsjkx,t1.[hkzt] as t1_hkzt,t1.[lcfkd] as t1_lcfkd,t1.[fkzlcid] as t1_fkzlcid,t1.[mode_top_4] as t1_mode_top_4,t1.[cgdj] as t1_cgdj,t1.[mode_top_22] as t1_mode_top_22,t2.[id] as t2_id,t2.[mainid] as t2_mainid,t2.[sld] as t2_sld,t2.[ppcj] as t2_ppcj,t2.[hsdj] as t2_hsdj,t2.[bz] as t2_bz,t2.[je] as t2_je,t2.[xhggyt] as t2_xhggyt,t2.[mxgxid] as t2_mxgxid,t2.[dqkckc] as t2_dqkckc,t2.[rkhkc] as t2_rkhkc,t2.[yf] as t2_yf,t2.[yldjbhyf] as t2_yldjbhyf,SELECT year(rksj) as 年 FROM uf_gfht as cus_年年 from uf_gfht t1 INNER join uf_gfht_dt1 t2 on t1.id = t2.mainid) tmp1 where t1 错在哪里
05-14

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值