Skip to content

ToplingZipTable

rockeet edited this page Jul 10, 2023 · 22 revisions

1. 简介

在 ToplingZipTable 中,有两个核心概念:CO-Index 和 PA-Zip

  • CO-Index: 即 Compressed Ordered Index,把一个类型为 ByteArray 的 Key,映射到一个整数 ID,这个 ID 用来访问 PA-Zip 中相应的那条 Value。
  • PA-Zip: Point Accessible Zip,可以看做是一个抽象的 array,核心功能是把 ID 作为抽象数组的下标,去访问该抽象数组的元素,当然,这些元素都是压缩存储的。

CO-Index 和 PA-Zip 一起,构成一个逻辑上的 map<Key, Value>

在这里,Key 是 RocksDB 中的 InternalKey: {UserKey, Seq, OpType} 三元组。

CO-Index 在 ToplingDB 中最典型的实现是 NestLoudsTrie,PA-Zip 在 ToplingDB 中最典型的实现是 DictZipBlobStore,两者都是内存压缩的,也就是说,它们在内存中的形态是压缩的,所有的搜索、读取操作都是在内存压缩的形态上执行的。并且 CO-Index + PA-Zip 的压缩率很高,远胜于 BlockBasedTable + zstd。

ToplingZipTable 压缩的计算开销较大(大约是 zstd 的两倍),所以,在 ToplingDB 中,主要是将它通过 DispatchTable 配置在 LSM 的较下层,并通过分布式Compact执行压缩。

2. 配置

配置项 类型 默认值 说明
localTempDir string /tmp ToplingZipTable SST 创建过程中会用到临时文件,这里指定临时文件目录
enableStatistics bool true 是否对 SST 的 Get 操作进行性能测量
keyPrefixLen int 0 MyRocks 等 DB 系统使用固定长度的前缀(一般为 4)来区分不同的表或索引,不同的表或索引,其数据特征一般不同,应使用不同的压缩方案
checksumLevel int 0 0: 不启用 checksum
1: 只对元数据启用 checksum
2: 对每条数据单独 checksum
3: 对整个文件整体 checksum
warmupLevel enum kIndex 打开 SST 时预热文件(加载到内存)
kNone: 不预热
kIndex: 预热 index
kValue: 预热整个文件(包括 value 内容)
debugLevel int 0 主要是为测试
sampleRatio float 0.03 采样率,因为 Value 的全局压缩需要采样
minPreadLen int 0 当 page fault 比较频繁时,使用 pread 性能会更好,因为需要的 IO 次数更少,并且避免了创建 PTE 的开销,该参数用来控制何时使用 pread
  < 0 : 不使用 pread
== 0 : 总是使用 pread
  > 0 : 大于该值时使用 pread
minPrefetchPages int 0 从 mmap 读取每条 value 时,如果 value 在文件中的尺寸较大(至少是跨了 Page 边界),一次性预读多少个 page,用来缓解随机访问时频繁的 page fault。0 表示禁用该功能,因为对 MADV_POPULATE_READ 的调用也有开销,在 page fault 很低时就没有必要
builderMinLevel int 0 LSM 中以该层为界,更顶层的不使用 ToplingZipTable, 更底层(含)的才使用 ToplingZipTable。
这是为了在使用分布式 Compact 时,如果分布式 Compact 失败后回退到执行本地 Compact,就要消耗 DB 结点的计算资源,而 DB 结点的计算资源是紧缺的,所以此时我们希望使用创建开销更低的其它 TableFactory(例如 SingleFastTable), 该参数就是主要为了实现这个目的
indexType string Mixed_XL_
256_32_FL
默认的 NestLoudsTrie 类型,NestLoudsTrie 可以使用不同类型的 Rank-Select 实现,主要用于测试,正常使用默认值即可
indexNestLevel int 3 NestLoudsTrie 索引的最大嵌套层数
indexNestScale int 8 NestLoudsTrie 每嵌套每加深一层,深一层的尺寸就会减少,减少到最外层的多少分之一时,就停止嵌套
  • 一般情况下嵌套层数越深,压缩比越高,搜索速度越慢,我们希望在压缩比和速度之间取得一个平衡
indexCacheRatio float 0 NestLoudsTrie 底层 Select 操作可通过 Cache 加速,此为 Cache 比例,一般设为 0.01 以下,搜索可以加速约 10%, 更多的 Cache 加速效果不明显
indexTempLevel int 0 创建 NestLoudsTrie 时,使用临时文件可以减小内存占用,使用的临时文件越多,需要的内存就越少
  • ToplingZipTable 曾经优先于创建非常大的索引,此配置项很有用
  • 现在 ToplingZipTable 不优先非常大的索引,此配置的用处已经不大了
indexMemAsResident bool false 让 index 常驻内存
indexMemAsHugePage bool false 让 index 使用 hugepage
speedupNestTrieBuild bool true NestLoudsTrie 创建时的优化参数,保持默认即可
optimizeCpuL3Cache bool true Value 的全局压缩使用了多线程 Pipeline, 该压缩算法的内存字典较大,在字典中对内存的访问很随机,该选项尽可能让单一 SST 的数据在同一时刻进行压缩,以提升 CPU L3 Cache 的利用率,该参数保持默认即可
bytesPerBatch int 256K 压缩 Value 时,Pipeline 中每个 Task 是一个 Batch,单个 Batch 中所有 value 的总尺寸
recordsPerBatch int 500 压缩 Value 时,单个 Batch 中所有 value 的数量上限
entropyAlgo enum kNoEntropy 使用全局字典压缩 Value 之后再使用熵编码压缩一次,熵编码的压缩收益很小,但是解压/读取的开销很大,所以默认关闭,不建议开启。其它可选值:kHuffman, kFSE
offsetArrayBlockUnits int 0 变长 Value 的定位通过 Offset 数组来实现,长度通过相邻 Offset 求差,该数组可以使用 PForDelta 压缩,该选项用来配置每个 PForDelta 压缩块的元素数量。0 表示不压缩;要压缩,首选 128, 还可设为 64, 不可设为其它值
minDictZipValueSize int 30 平均 Value 长度小于该值时,不压缩
keyRankCacheRatio float 0 用来加速 ApproximateOffsetOf, 设为 0 表示禁用,非零表示 Cache 从总体中的采样率
acceptCompressionRatio float 0.8 压缩后/压缩前 表示的 Value 的压缩率太差时,放弃压缩
nltAcceptCompressionRatio float 0.4 NestLoudsTrie 的压缩率太差时,放弃使用该索引,改用其它类型的索引
softZipWorkingMemLimit
hardZipWorkingMemLimit
smallTaskMemory
uint64 16G
32G
1.2G
多个 Compact 并发执行时,每个都需要内存,所以要进行限制,预期内存用量超过软限制时,允许单个预期内存用量不超过 smallTaskMemory 的新任务执行,达到硬限制时,任何新任务都不得执行
fileWriterBufferSize int 128K 写缓冲尺寸
fixedLenIndexCacheLeafSize int 512 对于 FixedLenKeyIndex, 配置其双数组查询缓存的叶节点尺寸,叶节点越大,缓存越小,保持默认即可
enableApproximateKeyAnchors bool true 启用 ApproximateKeyAnchors, 主要用于 debug

2.1. 示例

ToplingZipTable 是通过 SidePlugin 进行配置的,在(yaml)配置文件中,举例如下:

TableFactory:
  zip:
    class: ToplingZipTable
    params:
      localTempDir: "/dev/shm/tmp"
      indexType: Mixed_XL_256_32_FL
      indexNestLevel: 3
      indexNestScale: 8
      indexTempLevel: 0
      indexCacheRatio: 0
      warmupLevel: kIndex
      compressGlobalDict: false
      optimizeCpuL3Cache: true
      enableEntropyStore: false
      offsetArrayBlockUnits: 128
      sampleRatio: 0.01
      checksumLevel: 0
      entropyAlgo: kNoEntropy
      debugLevel: 0
      softZipWorkingMemLimit: 16G
      hardZipWorkingMemLimit: 32G
      smallTaskMemory: 1G
      minDictZipValueSize: 30
      keyPrefixLen: 0
      minPreadLen: 64

完整配置可参考 lcompact_enterprise.yaml

3. 小技巧:配置多个 ToplingZipTable

DispatcherTable 中,可以配置多个 ToplingZipTable,目的是采用不同的压缩选项,例如:

TableFactory:
  lightZip:
    class: ToplingZipTable
    params:
      localTempDir: "/dev/shm/tmp"
      indexNestLevel: 3
      indexNestScale: 8
      minDictZipValueSize: 10M

将 minDictZipValueSize 设得很大,这样就不会对单条 value 平均长度小于 10M 的数据进行压缩,适合 LSM 中较上层的数据(例如 2,3 层),不压缩除了可以降低 Compact 中的 CPU 消耗,还可以大幅提升读性能,因为不压缩不仅可以免去解压操作,还可以使用 ZeroCopy,直接将 SST 存储 value 的 mmap 内存返回给用户代码。

lightZip 不压缩 value,但仍会压缩 index(使用 CO-Index)