SSTable结构

SSTable文件是memtable 数据到一定阈值写入文件形成的,由于内存容量总是有限的,将一定量数据写入磁盘可以存放更多数据,所以leveldb相比redis能存放更多数据。既然数据持久化到磁盘,那么还有必然涉及到从磁盘中查询数据,从磁盘中查询数据与从内存中查询数据的效率是不一样的,所以SSTable 数据组织方式必然与众不同,因为必须要提高查询效率,不能给一个key就去遍历所有SSTable。因此本文的另一个目的就是学习SSTable 文件如何组织key-value,提高查询效率。为了提高内存中数据查询效率 我们学习了各种数据结构如红黑树,散列表,那么SSTable是学习如何提高文件查询数据效率的一个很好例子。

在学习源码之前还是先看看SSTable文件的结构 


整体上看 SSTable文件分为数据区与索引区,尾部的footer指出了meta index block与data index block的偏移与大小,index block指出了各data block的偏移与大小,metaindex block指出了filter block的偏移与大小。

1)data block:存储key-value记录,分为Data、type、CRC三部分 
2)filter block:默认没有使用,用于快速从data block 判断key-value是否存在 
3)metaindex block :记录filter block的相关信息 
4)Index block:描述一个data block,存储着对应data block的最大Key值,以及data block在文件中的偏移量和大小 
5)footer:索引的索引,记录metaindex block和Index block在SSTable中的偏移量了和大小

下面再具体看看各个部分物理结构

1、block 
sstable中data block 、metaindex block、index block都用这种block这种结构。对于data block,当block大小(record、restarts数组、以及num_restarts)超过4k时,就切换一个新的block继续往SSTable写数据,而metaindex block、index block就只有一个block,所以上图看起来data block有多个。 
 这里写图片描述
block主要由数据区record和restarts组成。 
为什么是这种结构? 
data block主要是存储数据,block内给一定数量(默认16)key-value分组,每组又用restarts数组记录起始位置,因此可以根据restarts读取每组起始位置key-value,由于block内的数据是从小到大有序存储的,所以可以通过restarts数组,获取每组起始key-value,比较起始key key(n)与查找的key大小,如果key(n)>key,那么key一定在序号>=n组之后,否则在 < n组之前。因此可以通过二分查找思想通过restarts获取起始key,来定位key的位置,避免线性查找低效。 
因此,restarts的思想就是提高block内key-value查找效率,直接定位key所在group。

下面再来看看record结构。record相对有意思,不是简单的用key-length | key-data | value-length|value-data存储。 
  这里写图片描述
 data block中的key是有序存储的,相邻的key之间可能有重复,因此存储时采用前缀压缩,后一个key只存储与前一个key不同的部分。重启点指出的位置即每组起始位置的key不按前缀压缩,而是完整存储该key。 
 type是表示数据是否压缩,以怎样的方式压缩,crc32是该block校验码,这个非本文分析重点。

2、index block 
index block 的结构也是block 结构,是data block的索引,记录每个data block 最大key 和 起始位置以及大小。具体的存储方式是以每个data block最大key 为key,以data block 起始位置和大小为value。因此可以根据每个block的最大key与查询key比较,直接定位查询key所在的位置。 
这是理论上key的存储方式,但是在sstable二次压缩的过程对key做了一个优化,它并不保存最大key,而是保存一个能分隔两个data block的最短Key,如:假定data block1的最大一个key为“abcdefg”,data block2最大key为“abzxcv”,则index可以记录data block1的索引key为“abd”;这样的分割串可以有很多,只要保证data block1中的所有Key都小于等于此索引,data block2中的所有Key都大于此索引即可。这种优化缩减了索引长度,查询时可以有效减小比较次数。 
 因此,index block的思想是提高SSTable内key-value查找效率,直接定位key所在block。

3、metaindex_block 
也是block结构。就只有一条记录,其key是filter. + filter_policy的name,value是filter大小和起始位置。

4、filter block 
filter block就是一个bloom filter,关于bloom filter原理概念可以百度。 
每个bloom filter是对data block 的key 经过hash num 次形成的字节数组,多少个data block对应多少个bloom filter。 
bloom filter实质就是一个bit 数组,对block 内key hash,将相应的位置设为1,这种设计关键在于能提高不存在的key判断效率,通过filter 计算,如果不存在,就不用通过data block内的restarts方式读取文件查找key是否存在,但是如果filter判断存在,还需通过restarts方式确定。 
5、footer 
footer位于SSTable文件尾部,占用空间固定为48个字节。其末尾8个字节是一个magic_number。metaindex_block_handle与index_block_handle物理上占用了40个字节,metaindex_block_handle和index_block_handle是BlockHandle数据类型, 这种结构用于记录metaindex block 和index block的起始位置和大小。 
 这里写图片描述
对于BlockHandle ,其实可以看作文件内容指针实现方式,BlockHandle记录数据位置及大小,与c/c++指针 思想类似,通过地址和大小可以读取数据。 
BlockHandle格式

varint64 offset | varint64 size_
采用变长存储,所以实际上存储可能连32字节都不到,剩余填充0。

总结,SSTable其实就是通过二次索引,先读取footer,根据footer中index_block_handler记录的index_block起始位置和大小,读取index block,通过index block 查询key所在data block,再在data block内部通过restarts 进一步确定key所在group。 
下面是完整的SSTable结构图 

这里写图片描述

猜你喜欢

转载自blog.csdn.net/ws1296931325/article/details/86635751