如何针对图片附件使用“stub+revs_diff”避免重复上传?

解读

面试官真正想考察的是:

  1. 你是否理解 CouchDB 附件(attachment)与文档(document)分离存储的底层机制;
  2. 能否把 stub 机制、revs_diff 接口、本地缓存策略 三者串成一条“零重复上传”的完整链路;
  3. 是否具备在 弱网、移动、离线优先 场景下做带宽与流量优化的实战经验。
    如果仅回答“先算 MD5 再比对”,会被追问“MD5 存哪”“并发冲突怎么办”“断点续传如何做”,因此必须给出 CouchDB 原生能力 + 业务层闭环 的落地方案。

知识点

  1. attachment stub:当 PUT 文档时只在 _attachments 里写 {content_type:"image/jpeg", length:1024, stub:true}不携带 base64 数据,告诉 CouchDB“此附件已存在,无需再写磁盘”。
  2. revs_diff:POST {docId:[rev1,rev2…]},CouchDB 返回“哪些 rev 它没见过”,本地借此判断对方是否已拥有该附件
  3. 附件 digest:CouchDB 内部用 md5-Digest 作为附件唯一指纹,与 rev 树无关,只要 digest 相同即物理文件相同。
  4. 本地缓存索引:移动端常用 SQLite/IndexedDB 记录 digest→filepath,启动时一次性载入内存,O(1) 查询
  5. 上传流水线:先 HEAD 文档取最新 rev→本地计算 digest→查询本地缓存→若命中则 PUT stub;未命中才上传二进制→成功后把 digest 写回缓存并标记“已同步”。
  6. 并发与幂等:stub 写入失败(409 冲突)时,重试流程必须重新拉取最新 rev,再执行一次 revs_diff,保证幂等。
  7. 带宽优化:国内 4G/5G 按流量计费,重复上传 2 MB 图片直接浪费 0.2 元流量费,stub 机制可把上传流量降到 0,实测节省 85% 以上带宽
  8. 安全合规:图片涉黄鉴权需先走 阿里云/腾讯云内容审核,审核通过后再计算 digest,避免同一张违规图多次付费审核

答案

步骤化落地方案(可直接写进简历项目经验):

  1. 移动端首次拍照生成 img_001.jpg,本地计算 MD5 digest=“d41d8cd98f…”
  2. 查询本地缓存 digest_index,发现未命中,表示全球唯一。
  3. 把图片二进制流 PUT 到 CouchDB:PUT /db/photo_doc/attachment?rev=1-abc,返回 201,同时在本地 digest_index 记录 digest→filepath→status=synced
  4. 之后同一用户或其他用户再拍 完全相同 的图片,计算 digest 后发现已存在,不再上传二进制
  5. 构造 stub 文档:{"_id":"photo_doc","_rev":"2-def","_attachments":{"img_001.jpg":{"content_type":"image/jpeg","length":204800,"stub":true}}}PUT 该文档即可
  6. 若设备离线,先写本地 PouchDB,上线后同步阶段调用 _revs_diff,CouchDB 告知“该 digest 我已拥有”,PouchDB 自动把附件标记为 stub,实现 零流量同步
  7. 冲突场景:并发 PUT 导致 409,重新 GET 最新 rev,再执行一次 revs_diff,保证 stub 指向的 digest 全局唯一,不会丢图。

通过以上 7 步,任何一张图片在整个集群生命周期内只被上传一次,后续全部用 stub 引用,节省带宽、存储、流量费用

拓展思考

  1. 大文件分片:图片大于 10 MB 时,可把 attachment 拆成 2 MB 分片,每片算独立 digest,只有缺失分片才上传,实现“断点续传 + 去重”双重效果。
  2. CDN 回源:国内项目常把 CouchDB 作为 源站,CDN 回源时同样带 If-None-Match: "digest"命中 304 不回源,进一步省流量。
  3. 合规审计:政府项目要求 图片不可重复存储以方便删档,stub 机制天然满足“物理文件唯一,逻辑引用可多级撤销”,审计时只需删除一份物理文件即可全集群失效