设计原则

设计文件系统时踩过的坑,让我总结出几条可以复用到其他系统的原则。

1. 元数据优先

原则

不要把文件系统只理解成"磁盘上的文件",业务依赖的是元数据。

实践

真正有价值的是 file_metadata:谁拥有这个文件、当前是否可访问、是否通过审核、生命周期到什么时候。元数据表要保留 status 字段,支持异步处理和审核,让文件 ID 与物理路径解耦。这样后续接对象存储、CDN 才不会推翻重来。

2. 控制面与数据面分离

原则

鉴权和元数据归业务服务,文件内容归存储平台。

实践

如果文件都经过业务服务中转,业务服务要承担上传带宽、连接压力和磁盘扩容。正确做法是客户端直传对象存储,业务服务只做鉴权、配额、签名和元数据。控制面理解用户和权限,数据面承载大文件和大带宽。

3. 状态机驱动一致性

原则

文件状态可追踪,用状态机和补偿任务修复不一致。

实践

对象上传成功但数据库更新失败、数据库有记录但对象不存在,这些都会发生。不要强行做分布式事务,而是通过状态机(created → uploading → uploaded → scanning → available)和补偿任务修复:超时清理临时对象、重新投递扫描任务、定期比对数据库和对象存储。

4. 幂等与可恢复

原则

上传可能失败,但绝不能让用户从头再来。

实践

断点续传的核心是可靠地识别同一个上传任务并知道哪些分片已可信。服务端要按分片编号、大小、hash 做幂等处理,重复请求直接返回成功。这样页面刷新、网络断开、浏览器崩溃后,用户能从已完成的部分继续。

5. 校验不能只在前端

原则

前端限制只是体验优化,服务端必须重新校验。

实践

文件大小、类型、hash 都要在服务端校验。文件类型不能只信任扩展名,要结合 Content-Type 和文件头魔数判断;文件名不能直接用于磁盘路径,避免路径穿越。风险文件上传后进入异步扫描,扫描通过前不开放访问。

6. 私有文件不裸奔

原则

权限不能只靠"URL 足够复杂"。

实践

私有文件通过短期签名 URL 访问:业务服务校验权限后生成带过期时间的签名地址,由 CDN 或对象存储承载。文件访问级别要明确区分公开、私有、临时、隔离,并支持签名失效、CDN 缓存失效和风险处置。

7. 生命周期与成本治理

原则

从第一天就设计生命周期,而不是等成本失控。

实践

临时分片自动清理、删除先软删再物理删、长期不访问的文件转低频或归档存储。热文件、冷文件、临时文件要有不同的存储策略。文件系统的成本问题很隐蔽,必须提前设计。

8. 审计贯穿全链路

原则

上传、下载、删除、审核都要留下可追踪的记录。

实践

审计日志覆盖上传(用户/IP/hash/结果)、下载(用户/文件/来源/签名过期)、删除(操作人/原因)、审核(结果/规则/人工处理)。审计日志与业务主流程弱耦合,异步消费落库,避免审计系统故障拖垮上传。

文件系统设计 checklist

传输与存储:
✓ 上传失败可恢复,未完成分片自动清理
✓ 文件 hash / 大小 / 类型服务端校验
✓ 元数据与二进制分离,对象 key 不含原始文件名

分发与访问:
✓ 业务服务避免承载大文件下载流量
✓ 私有文件只通过短期签名 URL 访问
✓ CDN 有版本化 / 刷新 / 回源保护

安全与治理:
✓ 上传后异步扫描,扫描通过前不开放访问
✓ 审核失败或删除后 CDN 缓存被失效
✓ 审计日志覆盖上传 / 下载 / 删除 / 风险处置
✓ 生命周期与冷热分层控制成本

记住:

  • 文件系统的难点不在”接收一个文件”,而在持续处理增长
  • 传输、存储、处理、分发、治理各自承担合适的职责
  • 今天的方案不要堵死明天接入分片、对象存储、CDN 和审计的路