对象存储:文件链路的带宽脱离与元数据解耦¶
文件处理不仅是“存进去”,更是一条涉及上传授权 -> 原件承载 -> 产物派生 -> 生命周期管理的长链路。
1. 带宽脱离:应用服务的解压¶
严禁让业务应用承载大文件上传/下载的二进制流,这会导致连接池被长时间占用,甚至拖垮整个服务的 QPS。
- 预签名 URL (Presigned URL):业务服务仅负责鉴权与生成带时效的 Token。客户端拿着 Token 直接与对象存储(OSS/S3)交互。应用服务只出“票据”,不出“流量”。
- 分片上传 (Multipart Upload):针对 GB 级文件,必须采用分片上传逻辑。它解决的不是存储容量,而是断点续传的容错性:哪一片失败就重传哪一片,不必重头再来。
2. 对象模型:Key 的工程直觉¶
在对象存储中,没有真正的“目录”,只有 Key。Key 的设计直接决定了后续检索与治理的复杂度。
- 语义化 Key 结构:建议遵循
业务域/租户ID/对象类型/版本/文件名(e.g.,kb-raw/t42/doc108/v7/original.pdf)。 - 不可变性 (Immutability):通常建议将 Key 与文件 Hash 或 Version 绑定。不要在原地覆盖文件,而是通过数据库记录切换“当前活跃指向”,这能有效避免缓存一致性问题。
3. 产物派生:中间状态的治理¶
上传完成只是开始。一份 PDF 进入系统后,会派生出大量中间产物:
- 派生路径:
PDF 原件 -> OCR 文本 -> 预览缩略图 -> 结构化 Chunk。 - 治理同步:中间产物必须与原件共享生命周期逻辑。如果原件因合规被物理删除,关联的 OCR 文本与预览图必须同步清理,否则就会留下数据残留(Data Residue)。
4. 元数据入库:业务真相的锚点¶
对象存储回答“内容在哪”,数据库回答“内容是什么”。
- DB 记录的最小结构:必须包含
ObjectKey、FileHash(去重依据)、Size、MIME、Version、ProcessingStatus。 - 不一致性检查:系统必须能容忍“对象存在但 DB 无记录”(上传中断残留)和“DB 有记录但对象缺失”(清理逻辑漏洞)。
5. 排查顺序:从票据到一致性¶
- 查票据授权:预签名 URL 是否过期?客户端 Header(如
Content-Type)是否与签名时一致? - 查一致性断裂:数据库里的
ObjectKey是否真的存在于 Bucket 中?版本是否对应? - 查异步流水线:OCR 或切块 Worker 是否因为拉取对象超时而频繁重启?
- 查生命周期策略:是否因为错误的 Lifecycle 规则误删了仍被业务引用的历史版本?
结论: 对象存储是应用服务的泄压阀。好的文件架构是将二进制流从业务主链路剥离,让数据库只守元数据真相,让存储系统自理冷热归档。