专业的编程技术博客社区

网站首页 > 博客文章 正文

分布式Nosql数据库(六) - Rocksdb KV分离存储设计

baijin 2024-08-26 10:25:28 博客文章 4 ℃ 0 评论

背景

大value的存储场景下,Rocksdb不是一个合适的选择,Rocksdb在大value场景下容易出现一些问题:

  1. compaction不可控,对于大value写入而言,它容易产生写入流量过大导致L0满,compaction跟不上写入速度,导致compaction不可控。
  2. 写放大过大,大value写入容易产生写入流量过大,L0文件会非常快的写满,从而触发频繁的compaction,导致系统写放大快速增加。
  3. 读性能下降,大value意味着单个文件记录数变少、cache记录数变少,导致cache命中率降低。

KV分离

如上所示,在KV分离的设计中,类似于在原有Rocksdb的基本上增加了一个钩子(通过自定义TableBuilder实现),自定义的TableBuilder会在Flushh和Compaction过程中初始SST文件对应的table builder对象,当向该table builer对象写入key-value数据时,会判断value是否超过配置的阈值,如果没超过配置的阈值,直接把key-value写入原SST文件,如果超过配置的阈值,则将该value写入单独的Blob文件,并且将对应Blob文件的number和offset写入原SST文件中,最终原SST文件存储的是<key - number + offset>的索引,实际的数据存储在Blob文件中。

通过上述的设计,把大value的数据存储在Blob文件,而原SST文件保存的是长度非常小的索引信息,这样Rocksdb本身的Compaction开销就会变得非常可控,大value的读取时耗也相对稳定,只有一次读Rocksdb索引和一次读Blob文件的开销。

按我们线上生产环境的运营经验,当超过1KB的key-value记录数占比10%、数据量占比超过40%时,采用KV分离方案后,相比原Rocksdb存储,业务平均RT下降了60%,不过空间占用却增加了30% ~ 40%,空间占用增加的原因在于Blob文件的GC配置了固定的阈值,实际空间占用一定会比实际数据量多,以50%的GC触发阈值为例,则实际空间占用可能是实际数据量的2倍以上。

GC

整个GC包括两步,第一步是当Flush或Compaction时,通过收集的table properties信息更新每个Blob文件的实际数据量大小,第二步是后台定期遍历有效数据比例低于GC阈值的Blob文件,然后把这些低于GC阈值的Blob文件做rewrite重写,最终实现Blob文件中有效数据保持在合理的比例。

如上图所示,即为Flush或Compaction过程中,通过收集的table properties更新Blob文件数据量大小。

如上图所示,即为GC的处理流程,后台线程会不断遍历blob文件,找到低于GC阈值的blob文件,以上图为例,发现blob1和blob2两个文件有效数据比例低于阈值,则把两个文件做rewrite。

rewrite的处理中,会遍历所有Blob文件中的key,然后到原始Rocksdb中查找该key,判断是否存在或是否有效,如果存在或有效,则写入新的blob4文件,否则直接丢弃,与此同时,key对应的新的索引位置信息写入到一个batch中。

当Blob文件全部rewrite完成后,第一步更新Blob文件的版本记录,将新产生的Blob文件加入到Blob文件管理的版本中,第二步再将保存有索引信息的batch写入到原Rocksdb,并删除老的Blob文件,以此来保证GC过程中异常情况下的数据一致性和完整性。

总结

Rocksdb在大value存储场景下的Compaction开销和写放大问题使得它不是一个合适的选择,通过key-value分离的存储方式,使得它在大value存储场景下有一个比较好的表现,但是,key-value分离存储的方式却会影响范围查询的性能,使得它主要应用于点查询场景,在后续工作中,也可以根据业务需求,针对范围查询场景,从逻辑层面考虑Prefetch的处理,降低key-value分离存储对范围查询性能的影响。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表