如何压缩冷数据?

解读

在国内金融、政企、IoT 等 CouchDB 落地场景中,冷数据通常指 90 天~1 年未被读写、但仍需保留合规的 JSON 文档。面试官问“压缩”不仅是磁盘瘦身,更关注合规、可逆、零停机、可回滚四个硬性指标。回答必须给出“CouchDB 原生能力 + 国内机房限制 + 审计要求”三位一体的落地方案,而不是简单一句“gzip 一下”。

知识点

  1. CouchDB 存储模型:B+ 树追加写,删除/更新产生旧版本(tombstone & revision tree),冷数据实际=大量历史 revision + 未被压缩的附件。
  2. 国内等保 2.0 要求:冷数据压缩后仍须可秒级还原哈希校验操作审计日志 180 天以上。
  3. 压缩层级
    • 文件系统层:ZFS/zstd、ext4 + e4defrag,需运维权限,不适合云托管版 CouchDB
    • CouchDB 内置_compact 仅清理 tombstone,不会跨 revision 去重_replicate 过滤同步可把冷库缩到最小。
    • 业务层:按“库-分区-日期”切分,历史分区离线压缩成 带签名的 tar.zst,原库删除并保留 digest + 审计链
  4. 附件二次压缩:JSON 附件若原为 base64,先转二进制再 zstd,平均再降 40%;压缩后把 content_type 改为 application/zstd,并写入 x-couch-attachment-meta:{compressor:'zstd',level:3,sha256:'...'}
  5. 还原链路:国内机房常禁外网,压缩包必须存入内网 MinIO 或华为云 OBS 私有桶;还原时通过 _bulk_docsnew_edits:false 写回,确保 revision 不变。

答案

分五步落地,全部可在零停机下完成:

  1. 识别冷范围:用 _find + 索引 {"lastAccess":{"$lt":"2023-06-01T00:00:00"}} 拉出 docid 列表,写入本地冷名单文件,MD5 留痕
  2. 冷分区复制:新建 db-cold-2023q1 库,通过 _replicate + doc_ids 把名单内文档拉过去,开启 create_target":true"batch_size":2000,复制完做一次 _compact 清理 tombstone。
  3. 附件二次压缩:写 Node 脚本遍历 db-cold-2023q1,对 ._attachments>10 kBcontent_type≠application/zstd 的附件:
    • 下载二进制 → zstd level=3 → 计算新 sha256 → 更新附件 stub → 把原 content_type 记录到 x-couch-attachment-meta
      脚本每更新 500 条调用 _bulk_docs 并写审计日志(docid、旧长度、新长度、sha256、操作人、时间)。
  4. 离线打包:对压缩后的 db-cold-2023q1couch-backup 导出 .couch 文件,再用 zstd -19 --long 压成 db-cold-2023q1.tar.zst附加 gpg 签名(国密 SM2 亦可),上传至内网对象存储,桶策略设为“写后锁定 1 年”。
  5. 原库瘦身:确认 tar.zst 哈希入库后,在原库通过 _purge 接口批量清除已冷 docid(需先关集群同步,避免 purge 扩散),再执行 _compact 释放空间;最后把冷名单、哈希、签名、操作人、审批单号写入 MySQL 审计表,保留 3 年供等保抽查。

还原时反向操作:下载 tar.zst → 验签 → 解压 → couch-restore 到临时库 → 用 _replicate 拉回生产库("create_target":false),revision 与原号段一致,业务无感。

拓展思考

  1. 如果集群是 CouchDB 3.x 分片 + 腾讯云 CBS 盘,第 4 步可直接用 云盘快照 替代 tar.zst,快照链自带加密与定时策略,节省 30% 运维量,但需解决快照跨账号审计问题。
  2. 附件大于 100 MB 的冷视频,可拆出到 自研 MinIO+EC 冷存,CouchDB 仅保留 external 类型附件存根,实现 “DB-对象存储” 混合压缩”,此模式在广电与医疗影像场景已落地。
  3. 未来升级到 CouchDB 4.x,官方实验性支持 Pluggable Storage Engine,可引入 RocksDB + zstd 字典训练,对冷分区自动切换引擎,实现在线透明压缩,届时上述脚本可退化为一条 PUT /{db}/_settings {"storage":"cold_rocks"} 即可,值得持续关注。