关键决策

这一页整理文件系统设计过程中遇到的关键决策点,每个决策都说明了问题、对比过的方案和最终选择理由。

决策 1:本地存储还是对象存储

问题

文件放在业务服务器本地磁盘,还是专门的存储平台?

方案对比

  • 本地磁盘:实现快、依赖少,但扩容难、备份难、多机不一致。
  • 对象存储:弹性扩容、自带备份和跨地域访问,但引入网络调用和成本。

决策

早期用本地存储快速起步,但文件量增长后必须迁移到对象存储。判断标准:业务服务器是否开始承担磁盘扩容、文件备份、下载带宽、跨机房同步这些不该承担的职责。对象 key 用 uploads/{tenant}/{yyyy}/{mm}/{dd}/{file_id}.{ext},避免同名覆盖、支持按租户日期治理。

决策 2:服务端中转还是客户端直传

问题

文件是经过业务服务转发到存储,还是客户端直接上传到存储?

方案对比

  • 服务端中转:实现简单、便于加逻辑,但业务服务承担上传带宽和连接压力。
  • 客户端直传:业务服务只出签名,文件流量直接到对象存储,压力最小。

决策

客户端直传对象存储。业务服务校验权限和配额后生成短期签名,客户端用签名直传,上传完成回调业务服务。这样业务服务不再处理大流量文件内容,只处理控制面逻辑。这是”控制面与数据面分离”原则的核心落地。

决策 3:单次上传还是分片上传

问题

大文件(几百 MB)怎么上传才可靠?

方案对比

  • 单次上传:小文件足够,但大文件失败一次就从头再来。
  • 分片上传:拆成多个可重试的小任务,失败只重传失败分片。

决策

大文件必须分片 + 断点续传。用 upload_taskupload_part 两张表管理任务和分片状态,服务端按分片编号、大小、hash 做幂等。分片并发数要控制(3-6 个),避免占满用户网络或触发服务端限流。

决策 4:实时扫描还是异步扫描

问题

病毒扫描、内容审核这类耗时任务放在哪里执行?

方案对比

  • 实时扫描:体验直接,但拉长上传耗时,大文件尤其明显。
  • 异步扫描:上传完成后异步处理,不阻塞上传,但文件要延迟开放访问。

决策

异步扫描。上传完成进入 scanning 状态,把任务投递到队列由扫描服务处理。扫描期间下载接口返回”处理中”或只允许管理员访问。对大多数文件系统,异步扫描在体验和安全性之间更平衡。

决策 5:直接对象存储访问还是 CDN 访问

问题

下载流量走对象存储源站,还是加 CDN?

方案对比

  • 对象存储直连:实现简单,但离用户远、热门文件带宽成本高。
  • CDN 分发:边缘节点缓存,首字节快、降低源站压力,但有缓存一致性问题。

决策

公开大流量文件走 CDN,私有文件走签名 URL。CDN 缓存一致性用版本化 URL 解决(内容变化生成新 URL),比频繁刷新更稳定。私有文件由业务服务校验权限后生成短期签名地址,再交给 CDN 承载。

决策 6:文件一致性怎么保证

问题

对象存储和数据库之间出现不一致怎么办?

决策

不强行做分布式事务,用状态机和补偿任务修复uploading 状态超时未完成就清理临时对象;uploaded 迟迟未进入扫描就重新投递任务;定期比对数据库和对象存储,发现孤儿文件或悬挂记录。补偿能力决定了系统能否从不一致中恢复。

决策 7:上传任务如何识别同一个文件

问题

断点续传时,如何知道用户重新上传的是同一个文件?

方案对比

方式优点风险
文件名 + 大小计算简单容易误判
文件整体 hash准确大文件计算慢
分片 hash + 抽样 hash兼顾性能与准确实现复杂

决策

生产系统不用前端一次性算完整大文件 hash,而是抽样 hash 或边读边算,upload_id 缓存在本地。服务端仍做最终校验,不信任客户端。查询接口返回已完成分片编号列表,客户端只补传缺失部分。

决策 8:安全校验放在哪几层

问题

文件系统是攻击入口,安全能力如何分层?

决策

贯穿上传、存储、访问、删除全链路:上传前校验权限、大小、类型和魔数;上传后异步扫描病毒和违规内容;访问前用签名 URL 做权限控制;发现风险立即置为 blocked、刷新 CDN 缓存、取消签名、保留证据。安全不是最后加一个开关,而是贯穿全链路的治理能力。