如何缓存预测结果到附件?

解读

在国内互联网/物联网/移动 App 面试中,面试官提出“把预测结果缓存到附件”并不是让你把模型跑在 CouchDB 里,而是考察三件事:

  1. 你是否理解 CouchDB 把“附件”当成二进制大对象(BLOB) 存储,且与文档原子绑定
  2. 能否用最小 IO 把高频、体积大的预测结果(图片、概率矩阵、Protobuf、ONNX 等)就近缓存到边缘节点,实现离线优先;
  3. 是否熟悉增量同步、冲突解决与版本控制,保证多端拉取时既快又一致。

一句话:把 AI 推理得到的只读大文件变成 CouchDB 附件,利用其多主复制能力做“模型结果 CDN”。

知识点

  1. 附件存储机制

    • 附件挂在文档 _attachments 字段下,独立流式存储,不占用 JSON 主文档大小限制
    • 上传时带 Content-Type,CouchDB 自动返回 Content-LengthETag,可做强校验缓存
    • 附件版本跟随文档版本,同一文档多附件可一次性原子提交
  2. 预测结果常见格式

    • 图片类:热力图、分割 mask → image/png
    • 结构化:Top-K 概率 → application/jsonapplication/x-protobuf
    • 模型本身:ONNX → application/octet-stream
  3. 上传方式

    • 直接 PUT /db/docid/attname?rev=xxx + 二进制 body
    • 使用 POST /db/docid/attname?rev=xxx&batch=ok 可关闭 fsync,降低 30% 延迟(国内云主机磁盘 IO 贵)
    • 批量场景用 _bulk_docsatt_encoding_info: true 可让 CouchDB 返回 stub,省一次往返
  4. 缓存与同步策略

    • 给附件名加“业务维度_时间戳_哈希”三段式,如 user123_20250618_7d3f4bc9.png,天然幂等,避免冲突
    • 客户端首次请求带 If-None-Match 头,利用 ETag 做 304 缓存;离线场景把附件落本地 PouchDB,先读本地再回源
    • 对超大附件(>5 MB)启用 gzip=true 压缩,国内移动端 4G/5G 平均省 40% 流量
  5. 安全与治理

    • 附件只读:在 design doc 里写 validate_doc_update 函数,禁止 _attachments 字段被普通用户覆盖
    • 敏感数据走 HTTPS + 签名 URL(国内云厂商 Bucket 回源同理)
    • 生命周期:用 CouchDB 2.3+ 的 _purge 或外部定时任务清理 30 天前附件,防止磁盘爆掉

答案

步骤级回答,可直接背给面试官:

  1. 设计文档结构

    {
      "_id": "pred_user123_20250618",
      "type": "prediction",
      "modelVer": "v2.1",
      "createdAt": "2025-06-18T14:30:00Z",
      "_attachments": {
        "heatmap.png": {
          "content_type": "image/png",
          "data": "<base64>"
        }
      }
    }
    
  2. 上传(curl 示例,国内 CentOS 默认带 gzip)

    curl -X PUT http://localhost:5984/predictions/pred_user123_20250618/heatmap.png \
         -H "Content-Type:image/png" \
         -H "If-Match:2-7d3f4bc9" \
         --data-binary @heatmap.png
    

    返回 {ok:true, rev:3-xxx} 即成功。

  3. 客户端消费

    • 在线:GET /predictions/pred_user123_20250618/heatmap.png
    • 离线:PouchDB 先 db.getAttachment 读本地,无网也秒开;网络恢复后自动同步
  4. 冲突解决
    同一用户多次预测产生冲突时,以最新时间戳为准,在 validate_doc_update 里拒绝旧 rev 写入,保证附件与主文档一致。

  5. 性能调优

    • 云主机 SSD 盘贵,把 [couchdb] attachment_stream_buffer_size = 1048576 调到 1 MB,减少内核切换
    • 国内跨地域场景,用 CouchDB 3.x 的 shard+zone 把附件副本固定在离用户最近的 zone,延迟从 200 ms 降到 40 ms

拓展思考

  1. 如果预测结果每天 100 GB,CouchDB 附件存储成本高于对象存储,如何做冷热分层
    → 热数据(7 天)放 CouchDB 附件,冷数据转存至国内云厂商 OSS/COS,文档里只保留 URL 与签名,通过 validate_doc_update 保证字段不可篡改。

  2. 多端同时写附件导致冲突爆炸怎么办?
    → 把预测任务拆成“只写一次”模型:边缘节点只生成附件并写入本地 CouchDB,云端通过 _replicator 拉取,写权限单向,冲突自然消失。

  3. 需要秒级回滚错误预测?
    → 附件名带模型版本号,如 heatmap_v2.1.png,回滚时只需把文档 rev 指回上一版本,附件随文档原子回退,无需重新生成。

  4. 面试官追问“为什么不用 Redis 缓存?”
    → Redis 只能存小对象且不支持离线同步;CouchDB 附件方案兼顾“大文件 + 离线优先 + 多主复制”,在移动医疗、车载 IoT、电力巡检等国内场景已落地,是离线优先架构的事实标准

把以上五点展开,就能从“知道”变成“专家”,面试现场直接封神。