本文主要是介绍漫谈RocksDB(四)存储结构——翩若惊鸿,婉若游龙,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
前面几个章节已经分别说了下RocksDB的基础概念和相关操作,下面来说一说RocksDB的存储结构,根据文件的存储结构再去回过头了解下RocksDB的相关操作。
正文
文件介绍
-
*.log: 事务日志用于保存数据操作日志,可用于数据恢复
-
*.sst: 数据持久换文件(此处的例子没有生成sst文件是因为第一次写数据,数据量小没触发flush操作,数据都在内存的MemoryTable中)
-
MANIFEST:数据库中的 MANIFEST 文件记录数据库状态。Compaction过程会添加新文件并从数据库中删除旧文件,并通过将它们记录在 MANIFEST 文件中使这些操作持久化。
-
CURRENT:记录当前正在使用的MANIFEST文件
-
LOCK:rocksdb自带的文件锁,防止两个进程来打开数据库。
-
IDENTITY:id
-
LOG:统计日志
-
OPTIONS:配置信息
写操作先写WAL,再写memtable,memtable达到一定阈值后切换为Immutable Memtable,只能读不能写。后台Flush线程负责按照时间顺序将Immutable Memtable刷盘,生成level 0 层的有序文件(SST)。后台合并线程负责将上层的SST合并生成下层的SST。
Manifest负责记录系统某个时刻SST文件的视图,Current文件记录当前最新的Manifest文件名。 每个ColumnFamily有自己的Memtable, SST文件,所有ColumnFamily共享WAL、Current、Manifest文件,用户可以基于RocksDB构建自己的column families。很多应用程序把RocksDB当做库(libary),尽管他提供server或者CLI接口。
上面是文件的具体含义以及处理流程,下面讲一下MemoryTable以及SST两个主要的数据存储结构,其余的存储结构了解含义与作用即可,日常工作中基本上不太会需要了解实现细节。如果确实有需要的,大家可以自行学习下。
MemoryTable
RocksDB 的 memtable 的默认实现是一个 skiplist。skiplist 是一个有序的数据集,当业务场景是使用 range-scans 并且同时写入时,这是一个很有效的数据结构。
然而,一些应用程序不同时写入和扫描,而另一些应用程序根本不执行范围扫描。对于这些应用程序,skiplist可能无法提供最佳性能。因此,RocksDB 支持可插拔的 API,允许应用程序提供自己的 memtable 实现。
开发库提供了三个 memtable:
-
skiplist memtable,
-
vector memtable
-
前缀散列(prefix-hash) memtable。
Vector memtable 适用于将数据批量加载到数据库中。每个写入在向量的末尾插入一个新元素; 当它是刷新 memtable 到存储的时候,向量中的元素被排序并写出到 L0 中的文件。
前缀散列 memtable 允许对 gets,puts 和 scans-within-a-key-prefix 进行有效的处理。
如果非上面的两种情况,建议使用默认的skiplist即可。
Skiplist Memtable
基于Skiplist的memtable在多数情况下都有较好读,写,随机访问以及序列化扫描性能。除此之外,他还提供其他memtable没有的有用的功能,比如并发插入以及带Hint插入。
Hash xxxx Memtable
hash类型的Memtable有两种不同的实现,一种是HashSkipList,另一种是HashLinkList。正如他们的名字所描述的,HashSkipList用一张哈希表组织数据,每个哈希桶内都是一个的skiplist,而HashLinkList则是用一张哈希表组织数据,每个哈希桶内则是使用一个排序好的linkedlist。两种类型都是为了减少查询的时候的比较次数,而两者之间的差别其实就是skiplist与linkedlist的差别。一种好的使用例子是使用PlainTable SST格式结合他们,然后把数据存储在RAM FS里。
当做数据查询或者插入一个key的时候,目标key的前缀通过Options.prefix_extractor被提取出来,用于找到具体的哈希桶。在哈希桶里面,所有的比较都是完整(内部)key比较,跟SkipList的memtable一样。
使用基于哈希的memtable最大的限制就是做多个前缀扫描的时候需要拷贝和排序,这非常慢并且浪费内存。
SSTable
SSTable 是 Sorted String Table 的简称,是大名鼎鼎的 Bigtable 底层的数据存储格式。HBase以及Cassandra的底层硬盘存储也是基于此格式。
SSTable简介
SSTable 的格式为文件本身就是一个排序的、不可变的、持久的Key/Value对Map。其中Key和value都可以是任意的byte字符串。 KeyValue 对根据固定比较规则有序地写入到文件中,文件内部分成一系列的Blocks(Block 不会太大,可自定义,默认4KB,常见的是 64KB,RocksDB对应配置项:table_options.block_size),同时具有必要的索引信息。这样 就既可以顺序地读取内部 KeyValue 记录,也能够根据某个 Key 值进行快速定位。
如图所示,SST 文件从头到尾分成5个部分。
名称 | 占用空间 | 说明 |
---|---|---|
Footer | 固定48字节 | 指出 IndexBlock 和 MetaIndexBlock 在文件中的偏移量信息,它是元信息的元信息,它位于 sstable 文件的尾部 |
IndexBlock | 占用一个 block 空间 | 记录了 DataBlock 相关的元信息 |
MetaIndexBlock | 占用一个 block 空间 | 各个元信息的Block,包括Filter、Properties(整个table的属性信息)、Compression dictionary、Range deletion tombstone |
MetaBlock | 可能占用多个 block空间 | 存储布隆过滤器的二进制数据 及其他元信息数据 |
DataBlock | 可能占用多个 block空间 | 存储实际的数据即键值对内容 |
Block
从上面的表格可以看出RocksDB的SSTable除了Footer外其余都是使用Block进行存储的,Block在硬盘上存储的时候,会在实际数据之后加上5个字节的额外内容:compression type、crc,如下图所示:
Bloom Filter
这里再说一下MetaBlock中的Bloom Filter,Bloom Filter的作用是对于任意集合的key,基于BitMap可以用来构建一个bit数组的算法。给出任意key,这个bit数组可以用于决定这个key是不是可能存在或者绝对不存在于这个key集合,用来减少无用的查询次数,从而加快查询的速度。Bloom Filter具体的知识点可以查看我之前的文章-------------
Footer
以上各部分都是 Block 的结构,只有 Footer 不同,是一个定长的格式。
序列化后,Footer的长度固定,为48个字节(旧)或53字节(新),格式如下:
// legacy footer format:
// metaindex handle (varint64 offset, varint64 size)
// index handle (varint64 offset, varint64 size)
// <padding> to make the total size 2 * BlockHandle::kMaxEncodedLength
// table_magic_number (8 bytes)
// new footer format:
// checksum type (char, 1 byte)
// metaindex handle (varint64 offset, varint64 size)
// index handle (varint64 offset, varint64 size)
// <padding> to make the total size 2 * BlockHandle::kMaxEncodedLength + 1
// footer version (4 bytes)
// table_magic_number (8 bytes)
Footer 中的信息,指明了 MetaIndexBlock 和 IndexBlock的位置,进而找到 MetaBlock 和 DataBlock。
读取 SST文件的时候,就是从文件末尾,固定读取这48或53字节,进而得到了 Footer 信息。
总结
上文讲解的就是RocksDB相关的存储知识,基本上能覆盖到常用的部分,其余需要详细理解的小伙伴们可以按需学习,另外不是管MemoryTable还是SSTable都是LSM tree的基础组件,被广泛利用于各种LSM tree的实现中,所以还是值得学习下的。
最后路漫漫其修远兮,大数据之路还很漫长。如果想一起大数据的小伙伴,欢迎点赞转发加关注,下次学习不迷路,我们在大数据的路上共同前进!
最后挂个公众号二维码,公众号的文章是最新的,CSDN的会有些滞后,想追更的朋友欢迎大家关注公众号,谢谢大家支持。
公众号地址:
这篇关于漫谈RocksDB(四)存储结构——翩若惊鸿,婉若游龙的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!