rocksdb系列partitioned index filt
为什么需要partitioned index filters
当DB越来越大, index/filter block
所占用的内存越来越大,即使设置了参数cache_index_and_filter_blocks
(只把部分index/filter block放置在block cache中), 占较大内存的index/filter block
也会影响DB性能 1)占用本来用于缓存data block 的block cache 2 ) 在block cache获取不到时,从磁盘上加载并加入到block cache中,这会增加系统负担。
index/filter block会有多大
默认情况下, 单个SST file会有一个index/filter block,index/filter的大小取决于配置,一般来说如果一个SST256MB, 那么index/filter block对应的大小是0.5/5MB,这些明显大于data-block(4-32k)。 如果index/filter能一直在memory中、在整个SST生命周期中只需读一次, 这种是做好的。而不是和其他data block竞争block cache中的空间, 并且多次从磁盘上重新加载。
large index/filter的问题
在极端情况下,如果index/filter block 放在block cache, index/filter block会和data cache无休止的竞争block cache的的内存空间。 算一下: 一个5M的filter占用的空间可以缓存1000个data block(如果data block是4K),这会导致很多cache miss。 这些内存占用大的index/filter很容易互相把对方踢出cache block从而导致自身的cache miss, 这也是为什么只有很少一部分的index/filter block会实际被用到。
如果index/filter block被踢出cache,这些block需要从磁盘上被重新加载,并且这些大快的block 不能减少IO cost。一个简单的单个key的查找最多需要几个data block 就行, 但是这可能会导致加载大块index/filter block, 如果这个频繁发生,那么磁盘会有大量的时间都在服务于index/filter 块,而不是实际的data block
什么是partitioned index/filters
简单说来, 就是给index/filter分成小的block,然后在这些block再加一级索引。 当读index/filte时, 只把顶层的index加入到内存中,在需要的时候, 这些partitioned index/filter 利用顶层索引去定位小块的index/filter block, 然后利用其的做index/filter query。 这个顶层index 可以在heap中也可以由配置文件
参数cache_index_and_filter_blocks
决定
这种做法的优点
- 高cache hit, 更细力度的控制index/filter, 更好的使用cache 空间
- 更少的I/O util ,一旦发生了cache miss,只需要从磁盘读少量的index
- 不需要向index/filter做妥协: 没有partition的时候,降低index/filter占用空间的方法是牺牲精度, 比如设置更大的data block size或者设置更少的bloom bit, 这样就可以减少index/filters 的size。
这种做法缺点
- 更多的space: level-top index需要保存大约需要0.1-1%的index/filter size
- 更多的Disk IO: 如果top-level index 不在cache中, 需要直接去文件中读, 这会可能需要更多的I/O, 为了避免这种额外I/O,top-level index可以被保存在heap中或者保存在高优先级的cache中(高优先级的cache也就是不会轻易被踢出cache)
- 丧失空间局部性: 如果a workload 需要频繁且随机的访问一个SST文件, 那么在读的时候会分别读多个不同的index/filter partition, 相比于一次直接读取整个index/filter, 效率低一些。其实可以禁止到L0/L1的top index。