若附件大小超过 4 MB,CouchDB 默认会采用何种压缩或分块策略?

解读

国内面试官抛出“4 MB”这个阈值,并不是想让你背数字,而是考察你对 CouchDB 附件存储层实现细节的理解深度。
4 MB 是 CouchDB 内置的 chunk_size 默认值,当附件长度超过该值时,数据库会把二进制流切成多个 chunk 文档 并写入同一数据库,每个 chunk 文档仅包含一段不超过 4 MB 的 base64 编码数据。
切分后,主文档的 _attachments 对象里不再直接存放数据,而是存放一个 "follows" 指针,指向第一个 chunk;后续 chunk 之间用 "next" 字段串成单向链表。
整个流程对客户端完全透明,读写仍通过 HTTP 一次完成,但底层已经变成“分块 + 轻量级压缩(仅 base64 体积膨胀,无额外 gzip)”的存储方式。
面试官真正想听的是:你能否把“4 MB 触发分块、链表串联、无默认 gzip、对业务透明”这四点一次说清,并指出它带来的 compaction 与复制性能影响

知识点

  1. chunk_size 参数:可在 couchdb 配置段里调整,单位字节,默认 4 290 000 B(约 4 MB)。
  2. chunk 文档 id 规则"blob." + 附件摘要 + ".chunk." + 顺序号,确保同一附件块全局唯一。
  3. 读取路径:CouchDB 先加载主文档,遇到 "follows" 字段即顺序拉取 chunk 链表,在内存中拼装成完整附件流返回,客户端无感知。
  4. 压缩策略CouchDB 本身不对附件做强制 gzip;若需要减小网络开销,需在前置反向代理(如 Nginx)开启 gzip_static on 并注意 CPU 折损。
  5. compaction 影响:分块后,附件数据散落在多个内部文档,数据库压缩时必须同时重写所有 chunk 文档,导致单次 compaction IO 放大;国内云环境若使用 HDD 盘,容易触发长耗时告警。
  6. 复制与同步:chunk 文档与普通文档一样走 _changes feed,跨机房同步大附件时会产生大量顺序 GET,若带宽不足,移动边缘节点可能出现同步延迟;国内项目常通过 /_replicatorfilter 把大附件隔离到独立数据库,再配专线同步。

答案

当附件尺寸超过 4 MB 时,CouchDB 默认启用 内部分块(chunking)策略

  1. 将附件按 4 MB 大小切分为若干段,每段作为独立 chunk 文档写入库内;
  2. 主文档的 _attachments 中仅保留 "follows" 指针,chunk 之间以 "next" 字段形成链表;
  3. 整个过程中 不启用额外压缩,仅因 base64 编码带来约 33 % 体积膨胀;
  4. 读写接口仍保持 REST 一次请求,对应用完全透明。
    简言之:>4 MB 自动分块存储,链表串联,无默认 gzip,透明访问

拓展思考

  1. 国内私有云常把 CouchDB 当作离线端底座,如果终端通过 4G 回传 50 MB 日志附件,分块后会产生 12 个 chunk 文档,每个 chunk 一次 PUT,移动网络下容易出现“中间 chunk 失败导致整附件作废”的问题。
    解决思路:
    • 在客户端预切 2 MB 块,自己做重试与断点续传,落库后再用 "attname/n" 方式合并;
    • 或者把大文件放到对象存储,CouchDB 文档只存外链与签名,降低数据库体积。
  2. 若业务必须存大量高清图片,可调大 chunk_size 到 16 MB,减少 chunk 文档数量,compaction 速度可提升 30 % 以上;但单 chunk 越大,单次复制失败重试成本越高,需要在压缩耗时与网络稳定性之间权衡。
  3. 对于合规场景(等保 2.0),审计要求“传输与存储双重加密”,此时可在 Nginx 层开启 gzip + SSL,同时把 CouchDB 置于内网,仅暴露 443 端口;注意 gzip 对二进制附件收益有限,优先使用 对象存储 + KMS 加密 更划算。