如何针对图片附件使用“stub+revs_diff”避免重复上传?
解读
面试官真正想考察的是:
- 你是否理解 CouchDB 附件(attachment)与文档(document)分离存储的底层机制;
- 能否把 stub 机制、revs_diff 接口、本地缓存策略 三者串成一条“零重复上传”的完整链路;
- 是否具备在 弱网、移动、离线优先 场景下做带宽与流量优化的实战经验。
如果仅回答“先算 MD5 再比对”,会被追问“MD5 存哪”“并发冲突怎么办”“断点续传如何做”,因此必须给出 CouchDB 原生能力 + 业务层闭环 的落地方案。
知识点
- attachment stub:当 PUT 文档时只在
_attachments里写{content_type:"image/jpeg", length:1024, stub:true},不携带 base64 数据,告诉 CouchDB“此附件已存在,无需再写磁盘”。 - revs_diff:POST
{docId:[rev1,rev2…]},CouchDB 返回“哪些 rev 它没见过”,本地借此判断对方是否已拥有该附件。 - 附件 digest:CouchDB 内部用
md5-Digest作为附件唯一指纹,与 rev 树无关,只要 digest 相同即物理文件相同。 - 本地缓存索引:移动端常用 SQLite/IndexedDB 记录
digest→filepath,启动时一次性载入内存,O(1) 查询。 - 上传流水线:先 HEAD 文档取最新 rev→本地计算 digest→查询本地缓存→若命中则 PUT stub;未命中才上传二进制→成功后把 digest 写回缓存并标记“已同步”。
- 并发与幂等:stub 写入失败(409 冲突)时,重试流程必须重新拉取最新 rev,再执行一次 revs_diff,保证幂等。
- 带宽优化:国内 4G/5G 按流量计费,重复上传 2 MB 图片直接浪费 0.2 元流量费,stub 机制可把上传流量降到 0,实测节省 85% 以上带宽。
- 安全合规:图片涉黄鉴权需先走 阿里云/腾讯云内容审核,审核通过后再计算 digest,避免同一张违规图多次付费审核。
答案
步骤化落地方案(可直接写进简历项目经验):
- 移动端首次拍照生成
img_001.jpg,本地计算 MD5 digest=“d41d8cd98f…”。 - 查询本地缓存 digest_index,发现未命中,表示全球唯一。
- 把图片二进制流 PUT 到 CouchDB:
PUT /db/photo_doc/attachment?rev=1-abc,返回 201,同时在本地 digest_index 记录digest→filepath→status=synced。 - 之后同一用户或其他用户再拍 完全相同 的图片,计算 digest 后发现已存在,不再上传二进制。
- 构造 stub 文档:
{"_id":"photo_doc","_rev":"2-def","_attachments":{"img_001.jpg":{"content_type":"image/jpeg","length":204800,"stub":true}}},PUT 该文档即可。 - 若设备离线,先写本地 PouchDB,上线后同步阶段调用
_revs_diff,CouchDB 告知“该 digest 我已拥有”,PouchDB 自动把附件标记为 stub,实现 零流量同步。 - 冲突场景:并发 PUT 导致 409,重新 GET 最新 rev,再执行一次 revs_diff,保证 stub 指向的 digest 全局唯一,不会丢图。
通过以上 7 步,任何一张图片在整个集群生命周期内只被上传一次,后续全部用 stub 引用,节省带宽、存储、流量费用。
拓展思考
- 大文件分片:图片大于 10 MB 时,可把 attachment 拆成 2 MB 分片,每片算独立 digest,只有缺失分片才上传,实现“断点续传 + 去重”双重效果。
- CDN 回源:国内项目常把 CouchDB 作为 源站,CDN 回源时同样带
If-None-Match: "digest",命中 304 不回源,进一步省流量。 - 合规审计:政府项目要求 图片不可重复存储以方便删档,stub 机制天然满足“物理文件唯一,逻辑引用可多级撤销”,审计时只需删除一份物理文件即可全集群失效。