bigywater.tech
MongoDB · 16

压缩:snappy、zstd、zlib 下同一份数据占多少磁盘

同一份数据用 snappy、zstd、zlib 存,分别占多少磁盘?压缩有没有拖慢写入和扫描?这篇给每个集合指定不同的 block_compressor,用同一份 10 万条日志样的数据对比,再换成随机字节看压缩什么时候无效。

46% / 31%
snappy 与 zstd 下日志样数据的 storageSize 占 BSON 总大小的比例
37 → 91 ms
冷缓存全表扫描:snappy 对 zstd
102%
随机字节数据用 zstd 压缩后仍是 BSON 总大小的 102%

数据与方法

实测 · 本机执行输出
  样例: {'_id': 0, 'user': 3307, 'level': 'ERROR', 'ts': 1700000000, 'msg': 'xqmb oyjmxz nplvptva fshvmj aan ajhnmri …', 'host': 'srv-33'}

10 万条日志样的文档(约 19.8 MB BSON),放进 4 个集合,createCollection 时用 storageEngine.wiredTiger.configString 指定 block_compressor。

占多少磁盘

实测 · 本机执行输出
  压缩算法          dataSize   storageSize      占 BSON 的比例        磁盘文件大小
  none        19,784,644    20,647,936           104%    20,647,936
  snappy      19,784,644     9,158,656            46%     9,158,656
  zstd        19,784,644     6,217,728            31%     6,217,728
  zlib        19,784,644     6,934,528            35%     6,934,528

none 比原始数据还多 4%(页面开销);snappy 压到 46%,zstd 31%,zlib 35%。

默认值与索引

实测 · 本机执行输出
  c_snappy: block_compressor=snappy
  c_zstd: block_compressor=zstd
  test> db.adminCommand({getCmdLineOpts: 1}).parsed
  {
    net: {
      bindIp: '127.0.0.1',
      port: 9901,
      unixDomainSocket: { enabled: false }
    },
    storage: {
      dbPath: '/data/m8/db',
      wiredTiger: { engineConfig: { cacheSizeGB: 0.25 } }
    },
    systemLog: {
      destination: 'file',
      path: '/data/m8/mongod.log'
    }
  }
  没有指定压缩算法的集合 c_default: block_compressor=snappy
  索引的 creationString 里有 prefix_compression 吗: block_compressor=,prefix_compression=true,prefix_compression_min=4

不指定时集合用 snappy;索引不用块压缩,用前缀压缩(prefix_compression=true)。

写入耗时

实测 · 本机执行输出
  none         247 ms
  snappy       242 ms
  zstd         260 ms
  zlib         274 ms

插入 10 万个文档,四种算法都在 242~274 ms,差别不大。

读取耗时

实测 · 本机执行输出
  none          45 ms   (3 次: 47, 36, 45)
  snappy        37 ms   (3 次: 37, 33, 45)
  zstd          91 ms   (3 次: 81, 91, 92)
  zlib          88 ms   (3 次: 92, 87, 88)

清空 WiredTiger 缓存后全表扫描:snappy 与 none 接近,zstd 和 zlib 约慢一倍,因为解压更耗 CPU。

可压缩性

实测 · 本机执行输出
  随机字节文档的 BSON 总大小 22,200,000;
  none    storageSize   23,040,000  占 BSON 的 104%
  snappy  storageSize   22,925,312  占 BSON 的 103%
  zstd    storageSize   22,642,688  占 BSON 的 102%
  zlib    storageSize   22,646,784  占 BSON 的 102%

随机字节本身不可压缩,所有算法下都接近原始大小。压缩收益取决于数据重复程度,上线前要用自己的数据测。

分步演示

压缩算法对比
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MongoDB 9.0.2(Homebrew 的 mongod、mongos)/ mongosh 2.12.0 / pymongo 4.18.3;每个实验在临时目录里起全新的 mongod(独立 dbpath,端口 9900 以上,只监听 127.0.0.1,WiredTiger 缓存 0.25 GB),需要副本集或分片集群时在本机起多个进程;命令输出来自真实的 mongosh,批量写入、计时与多线程用 pymongo;计时用 time.perf_counter,数字每次运行会有小幅抖动,ObjectId、时间戳等每次运行都不同。数据由固定种子生成,每个集合只插入一次;冷缓存扫描是重启 mongod 后各测一次,3 轮取中位数,操作系统文件缓存仍然是热的
    • 没有验证:真正读磁盘(冷操作系统缓存)的扫描时间;更大数据集上的压缩比;zstd 的压缩级别配置;网络消息压缩(networkMessageCompressors)与日志压缩;journal 的压缩;不同数据形态(嵌套、长字符串、数值)下的压缩比;CPU 占用的具体数字
    京ICP备2026067502号-1京公网安备11010502063487号