LSM tree保证数据库有序写入(memtable-skiplist),它提高了写作性能,但由于其自身的分层结构,它牺牲了读写性能(一个key如果存储在低级别level,每一层都要从上到下搜索,成本极高)。因此,对于提高阅读性能有很多优化:bloom filter (高效判断一个key是否不存在),index-filter(二分搜索,低内存消耗)索引key-value数据。这些数据库需要存储SST用于文件中k-v有序管理数据。
1)Footer : 指出固定48字节 IndexBlock 和 MetaIndexBlock 位于文件中的偏移信息是元信息的元信息 sstable 文件的尾部
2)IndexBlock:占用一个 block 空间,记录 DataBlock 元相关信息
3)MetaIndexBlock:占用一个 block 空间,各元信息Block,包括Filter、Properties(整个table属性信息),Compression dictionary、Range deletion tombstone
4)MetaBlock:可能占多个 block空间,存储布隆过滤器的二进制数据 以及其他元信息数据
5)DataBlock:可能占多个 block存储实际数据的空间,即内容的键值
Footer位于固定48个字节的大小SSTable文件尾部;MetaBlockIndex和DataBlockIndex的offset和size组成BlockHandlel用于寻址的类型MetaBlockIndex和DataBlcokIndex块的位置,size和offset采用varint编码变长,节省空间,offset和size因此,至少占用一个字节长度,最多占用9个字节长度MetaBlockIndex和DataBlockIndex的offset和size最多占用4*9=36个字节,通过padding补充到40个字节(8字节对齐)DataBlockIndex.offset = 64、DataBlockIndex.size=216,表示DataBlockIndex位于SSTable第6464字节至280字节。
Block 结构
数据结构的五个部分,除了 Footer,其它物理结构都是 Block 形式。每个 Block 因此, Block 它的大小与磁盘存储块的大小也是Footer文件末尾的原因,Footer48个字节本身不能占用磁盘存储块。Block 在硬盘上存储时,在实际数据后添加5个字节:compression type、crc。
Data Block 结构
DataBlcok Key 前缀压缩机制用于存储,前缀压缩是 key 同样的前缀,尽量只存放一次,以节省空间。但是对于 SSTable 它不是整个 block 的所有 key 一次性压缩前缀,但在同一区域设置了多个区段 key 进行一次前缀压缩,每个区段的起点就是一个重启点。前缀压缩机制导致每个记录都需要记住相应的记录 key 共享长度和非共享长度。所 谓 key 共享长度是指当前记录 key 以上记录 key 公共前缀的长度 度,非共享长度则是去掉相同部分后的不同部分的长度。这样,当前的记录只需要存储不同的部分 key 的值即可。
第一部分(Entry)用来存储key-value数据。由于sstable中所有的key-value是的,它们严格按顺序存储,用来节省存储空间,而不是每对key-value全部储存key相反,存储值与上一个相同key避免了非共享部分key存储重复内容。每隔几个key-value是的,将重新存储完整的记录key。重复过程(默认间隔值为16),每次重新存储完整key的点称之为Restart point。
Restart point目的是读取sstable内容时,加速查找的过程。由于每个Restart point储存完整key值,因此在sstable在数据搜索中,可以先使用restart point对点数据进行键值比较,以便快速定位目标数据所在区域;确定目标数据所在区域时,对区间内的所有数据项进行逐项比较key值,细粒度搜索;这个想法有点类似于跳表中快速定位高层数据、详细搜索底层数据的想法,降低了搜索的复杂性。
KV 数据存储结构
- shared key length: 与 restart point 相同的key前缀字节长度。
- unshared key length: 当前key减去restart point 前缀长度相同后,剩余字节长度
- value length: 字节长度值
- unshared key content: key与restart point中的key不同部分的key内容.
- value: 存储真实值
Index Block 结构
index block包含多个记录,每个记录代表一个data block用于快速定位包含特定特定索引信息的索引信息key的Data Block;Index Block首先是一个block,因此,它包含三个部分KeyValue、Type(固定1字节),CRC检验码(固定4字节);Type用压缩算法识别这部分数据,CRC是KeyValue Type的检验码。
索引包括以下内容:
- key,值大于或等于索引block的最大key,小于下一个block的最小key;
- 该data block起始地址在sstable中偏移量;
- 该data block的大小;
IndexBlock和 DataBlock 前缀压缩是一样的,但间隔是2(DataBlock 默认为16)。
假设索引的主要目的是节省空间;block的最大key为"acknowledge",下一个block最小的key为"apple",如果DataBlockIndex的key采用其索引block的最大key,占用长度为len("acknowledge");采用后一种方法,key值可以为"ad"("acknowledge" < "ad" < "apple"),长度仅为2,检索效果相同。
因为SSTable中的block大小不固定,虽然option中可以指定block_size参数,但SSTable存储数据时,没有严格遵守block_size对齐,所以offset和size指偏移字节数和长度字节数。主要有两个原因:
(1)可以存储任何长度key任何长度value,而同一个key-value是不能跨block在极端情况下,如我们的单个存储 value 它很大,已经超过了 block_size,所以对于这种情况,SSTable 就没法进 行存储了。所以通常,实际的 Block 大小略大于 block_size 的;
(2)从另一个角度个角度block_size对齐存储数据必须有很多block通过补0对齐,浪费存储空间。