cswork / 系统设计

第 40 章 / 共 57 章 · 约 4 分钟

设计模式:大文件处理

本页目录
  1. 1. 上传:预签名 URL 直传
  2. 2. 大文件和弱网:分段与断点续传
  3. 3. 下载:CDN 加签名 URL
  4. 4. 后处理
  5. 5. 一致性和清理
  6. 6. 常见追问
  7. 7. 本站用到这个模式的案例
  8. 章节测验

照片、视频、附件、数据集这类大文件,如果走“客户端 → 应用服务器 → 存储”的老路,应用服务器的带宽、内存和连接会被一点点耗尽,一次网络抖动就要从头再传。这一章讲大文件上传、下载和后处理的标准做法:让字节直接在客户端和对象存储之间流动,应用服务器只负责授权和记账。

1. 上传:预签名 URL 直传

  1. 客户端请求上传:POST /uploads {filename, size, content_type}。
  2. 应用校验权限和大小,在数据库写一条状态为 PENDING 的记录,生成对象 key,签发一个有时效的预签名 URL(大文件则签发分段上传的每一段的 URL)。
  3. 客户端直接 PUT 到对象存储。
  4. 对象存储的事件通知(或客户端调用 complete)告诉应用上传完成,应用校验大小和哈希后把记录改为 UPLOADED,并触发后处理。
预签名 URL 直传和后处理
滚动到此处后加载图表…
图表可横向滚动,展开后可缩放查看。
查看图表源码
flowchart LR
  accTitle: 预签名 URL 直传和后处理
  c["客户端"] -->|"1. 申请上传"| api["应用服务"]
  api -->|"2. 写 PENDING 记录"| db[("元数据库")]
  api -->|"2. 预签名 URL"| c
  c -->|"3. 直接上传字节"| s3[("对象存储")]
  s3 -->|"4. 上传完成事件"| q["队列"]
  q --> proc["后处理 worker:校验、转码、缩略图"]
  proc --> db
  cdn["CDN"] --> s3
  viewer["查看者"] -->|"签名的下载 URL"| cdn

2. 大文件和弱网:分段与断点续传

  • 分段上传:几 GB 的文件切成 5–100 MB 的段并行上传,失败的段单独重传,全部完成后合并。
  • 断点续传:客户端记住已完成的段(或向服务端查询),网络恢复后只传剩下的。手机上传视频时尤其重要。
  • 分块加哈希:把文件切成固定大小的块,每块计算哈希。已经存在的块不必再传(去重),修改文件只需上传变化的块,这是网盘同步的基本思路。

3. 下载:CDN 加签名 URL

  • 公开内容(商品图片、公开视频)直接经 CDN 缓存分发。
  • 私有内容保持桶私有,由应用为有权限的用户签发短时效的下载 URL,或使用 CDN 签名 Cookie。
  • 视频切成几秒一段的小文件(HLS/DASH),播放器按网速选择码率,每段都能被 CDN 缓存;拖动进度条只需请求对应的段。
  • 大文件下载支持 Range 请求,可以断点续传、多线程下载。

4. 后处理

  • 上传完成事件进入队列,worker 做病毒扫描、格式校验、生成缩略图、转码、提取元数据,按长时间运行的任务来设计:幂等、可重试、失败进入死信队列。
  • 处理结果写回对象存储(新的 key),元数据库记录各个版本的位置和状态。
  • 处理完成前,用户看到的是“处理中”,而不是一个打不开的文件。

5. 一致性和清理

  • 记录有、文件没有:上传从未完成的 PENDING 记录,超过时限由定时任务清理。
  • 文件有、记录没有:上传了但没有确认的对象,用生命周期规则(例如上传目录下超过 1 天的对象自动删除),或者定期对账清理。
  • 防篡改:签发 URL 时限定 content-type 和大小上限;完成时校验客户端声明的哈希。

6. 常见追问

  • 为什么不让文件经过应用服务器? 一个 1 GB 的上传会占住一个连接几分钟,几百个并发上传就能打满服务器的带宽;直传把这部分负载交给了几乎无限扩展的对象存储。
  • 预签名 URL 泄露了怎么办? 有效期设短(几分钟),只授权一个具体的 key 和操作,泄露的影响很有限。
  • 怎么限制用户的存储配额? 申请上传时按声明的大小预留配额,完成时按实际大小结算,未完成的超时释放。
  • 同一个文件很多人上传? 用内容哈希做 key,相同内容只存一份,按引用计数删除。

7. 本站用到这个模式的案例

章节测验

5 道选择题
  1. 在预签名 URL 直传的流程里,应用服务器负责什么?
  2. 用户在手机上上传 3 GB 视频,地铁里网络时断时续。最重要的设计是?
  3. 有些 PENDING 记录对应的上传永远没有完成,也有些对象上传了却没有被确认。怎么处理?
  4. 视频切成每段几秒的 HLS/DASH 小文件来分发,主要好处是?
  5. 预签名上传 URL 被别人截获了,怎样从设计上降低影响?

章节讨论

正在加载讨论…