leveldb切rocksdb中遇到的那些坑

举报
风做了云的梦 发表于 2022/12/27 11:27:55 2022/12/27
【摘要】 LevelDB与RocksDB都是一种持久化存储的KV系统,RocksDB是基于LevelDB进行开发的,二者都是基于LSM-tree(Log Structured Merge Trees)的结构进行存储。

1 LevelDBRocksDB简介

        LevelDB与RocksDB都是一种持久化存储的KV系统,RocksDB是基于LevelDB进行开发的,二者都是基于LSM-treeLog Structured Merge Trees)的结构进行存储。如下图所示,LevelDBRocksdb写数据时,都是通过先将数据记录到WAL中,用于发生故障时进行恢复,再将数据写入内存中的Memtable,等到Memtable中数据写满之后,Memtable会转变成Immutable MemtableImmutable Memtabledump成底层存储文件(SSTable,在LevelDBldb为后缀结尾,在RocksDB中以sst为后缀结尾)。读取数据时,会优先读取内存中Memtable中的内容,没有再依次去查找Immutable Memtable,和底层存储文件(包含一些存储结构cache中的查找操作),由于底层存储文件是分层存储的,并且每层存在多个SSTable,会依次查找每层的每个SSTable,因此在LevelDBRocksDB中,写性能都优于读性能。

222.jpg

RocksDB的优势

2.1  Memtable

        Memtable是在内存中存储k-v记录的表,LevelDB在内存中只有一个Memtable,来不及刷盘便会造成写入时系统卡顿,而RocksDB可以设置多个Memtable,当一个Memtable写满了后,立即创建一个新的Memtable,后续写入会写到新的Memtable中。Memtable的数量可以进行调优。

2.2  Compaction

        为了加速LevelDBRocksDB的读性能,二者都在底层进行了Compaction操作。在LevelDB中主要包含Minor Compaction(用于将Immutable Memtable dump到磁盘中的存储文件中,对应于RocksDB中的Flush)和Major Compaction(用于整理底层存储文件,清理一些无效的记录和数据)两种Compaction操作。RocksDB中的Compaction主要指Major Compaction,同时RocksDB提供了很多中Compaction策略,默认为Level CompactionCompaction主要通过挑选level n-1层的sstlevel n层的sst文件,将level n-1层的文件与level n层的sst文件进行合并,将数据一层一层下沉。当然,频繁的Compaction可能也会带来一些性能问题,造成cache的失效。

        LevelDB后台是单线程的,只能单线程合并文件,各种Compaction任务会加到任务队列依次执行,而RocksDB提供了多个线程,将Flush线程和Compaction线程分开, 在刷盘的同时可以进行多线程合并底层存储文件。RocksDB还为线程池提供了优先级管理,有着优秀的线程调度。频繁的Compaction操作伴随着SST的写入,会带来较大的IO压力,因此可以针对项目进行Compaction速率的调优。同时,RocksdDB中的后台线程也是可以停止的,可以通过调用PauseBackgroundWork()ContinueBackgroundWork()灵活控制后台线程的停止和启动,但是需要注意的是这里会停止所有的后台线程(包含flush线程与compaction线程),停止flush线程后,继续执行写操作,在内存中的Memtable写满后,会卡住,调用ContinueBackgroundWork()之后,恢复正常。由于底层存储文件第0层是无序的,不同的SST存在重叠的情况,所以不能并行,RocksDB提供了subCompaction,将第0层并行合并到第1层,默认没有开启,后续可以针对此处进行优化。

2.3  其他优化

        RocksDB支持一次获取多个k-v, 并且支持在合并的时候使用过滤器对无效记录进行过滤,以及一些解析底层存储文件sst的工具供开发者使用,同时你可以直接创建底层存储文件sst, 通过SstFileWriter直接将创建的sst导入到RocksDB

LevelDB迁移到RocksDB

        LevelDB与RocksDB大部分接口都是兼容的,磁盘上的目录结构也是相似的,迁移相对容易。在创建数据库时,如果需要保持和以前的配置大致相同,可以使用rocksdb::LevelDBOptions将之前的leveldb::Options对象转化为rocksdb::Optionsoptions里包含了数据库的一些配置选项。需要注意的是,RocksDB中存在了列簇(column family)概念,会对数据库进行逻辑上的划分,可以将不相关的数据结构存储在同一个DB中,因为LevelDB没有此概念,迁移到RocksDB之后,默认不设置,会将数据都存储到default列簇中。

111.png

        如果设置多个列簇,那么它们分别有自己的MemtableImmutable Memtable,以及相同的存储文件,但是会共同写入同一个WAL中。对于Memtable的数量和后台线程的个数可以根据自己的项目进行设置。

        在迁移过程中遇到一个问题,我们的项目中,创建了较多数量的LevelDB实例,当我们迁移到RocksDB之后,发现程序启动后,存储空间会上涨几个G的大小,通过ls查看RocksDB目录文件,并没有发现异常,但通过du命令查看会发现,RocksDB的日志文件在没有存储任何东西的情况下直接就会占到71M的大小(ls查看的是文件实际大小,而du查看的是文件实际占用磁盘的空间大小),通过查阅资料发现,LevelDB中默认配置Memtable大小为4kb,而RocksDB内存中的Memtable大小为默认为64M,为了防止磁盘没有空间写,提前为RocksDB的日志在磁盘上进行了预分配,如果不希望占用这么多空间,可以通过RocksDB::Options中的write_buffer_size调整Memtable的大小,进而影响日志文件在磁盘中预分配的大小。


 

 

 

 

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。