当文档历史超过 1000 个版本时,如何触发“compact”以缩减元数据?

解读

面试官真正想考察的是你对 CouchDB MVCC(多版本并发控制)机制数据库文件膨胀之间关系的理解,以及你是否能在国内常见的“离线优先+移动同步”场景下,主动用运维手段代码策略把历史版本数降下来。
“1000 个版本”并非官方硬编码阈值,而是国内很多落地项目把 revs_limit 调到 1000 后,发现 .couch 文件暴涨、同步流量陡增的经验临界点。因此,回答必须同时覆盖“调参”和“触发压缩”两条线,并给出可落地的脚本或定时任务方案。

知识点

  1. MVCC 与 revs_tree:每次更新都追加一个新版本,旧版本仍在文件里,直到压缩。
  2. revs_limit:单文档保留的最大版本深度,默认 1000;调小可直接减少历史。
  3. 压缩(compaction):把旧版本、已删除的文档和视图的旧索引一并清理,生成新的 .couch 文件并原子切换。
  4. 触发方式
    • HTTP POST /{db}/_compact(需管理员权限
    • couchdb -c 命令行(单机版)
    • 调度器_scheduler/compaction2.x+ 版本自带,可配 cron 表达式)
  5. 国内云厂商限制:阿里云、腾讯云托管版 CouchDB 通常关闭外部 _compact 权限,需提工单或在控制台勾选“自动压缩”。
  6. 移动同步场景:PouchDB 默认 revs_limit: 1000,若业务方频繁更新,手机端 DB 体积先爆炸,需在网关层提前压缩下调 revs_limit 到 50~100

答案

分三步走,线上无中断完成:

  1. 调小 revs_limit(提前削顶)
    curl -X PUT http://admin:pass@localhost:5984/your_db/_revs_limit -d '100'
    
    这一步立即生效,但旧版本仍占磁盘。
  2. 触发数据库压缩(真正释放空间)
    curl -X POST http://admin:pass@localhost:5984/your_db/_compact \
         -H "Content-Type: application/json"
    
    返回 {"ok":true} 后,CouchDB 会在后台线程执行;可通过 GET /_active_tasks 观察进度。
  3. 国内生产环境自动化
    • 自建集群:在 local.ini 里打开 [compactions] 段,写一条
      _default = [{db_fragmentation, "70%"}, {view_fragmentation, "60%"}, {parallel_view_compaction, true}]
      
      并配 cron = 0 2 * * * 每天凌晨 2 点自动检查。
    • 托管版:若云厂商屏蔽 API,把步骤 1 的 revs_limit 降到 50~100,然后提交工单申请“后台压缩”,一般 1 h 内完成。

注意:压缩期间磁盘需预留 2×当前库大小的剩余空间,国内 SSD 云盘成本敏感,务必提前扩容。

拓展思考

  1. “1000”不是银弹:国内某物流 APP 把 revs_limit 设成 30,配合每日自动压缩,一年节省 62% 存储费用,移动端同步流量下降 45%。
  2. 分片集群下的压缩顺序:BigCouch 或 3.x 集群先压缩各分片副本,再压缩视图;若副本正在同步,压缩会自动重试,但会拉长窗口,需在 SLA 里预留 30 min 抖动。
  3. 与备份的权衡:压缩后旧版本永久消失,若业务需审计回溯,可在压缩前用 couchbackup 做一次增量快照到 OSS,国内合规场景常用。