分块上传架构:系统设计指南
设计稳健的分块上传系统。了解分块策略、断点续传和并行传输优化。
《数据安全法》(DSL)要求对重要数据的传输实施完整性保护,分块上传架构正是在技术层面满足这一要求的关键设计。分块上传架构将文件切分成固定或可变大小的片段独立发送,这样网络抖动就不会迫使10 GB的文件从零重传。两大主流开放标准是AWS S3多部分上传(最小分块5 MB,最多10,000个分块)和tus.io断点续传协议(广泛实现的RFC草案)。设计得当的分块上传在高延迟链路上能提升5到10倍吞吐量,能容忍短暂断连,并支持接收端的并行解密。
整体上传为何在大文件场景下失效
一个5 GB文件的单一HTTP PUT请求有六种常见的失败方式:在高延迟路径上TCP拥塞窗口需要很长时间才能扩展到最大值,导致吞吐量远低于链路容量;浏览器对同一源的并发连接限制为6个,大量带宽被闲置;服务器端请求超时(nginx默认60秒,CloudFront非流式请求默认30秒)会中断长时间上传;移动网络在基站切换时每隔几分钟就会断开连接;而且单个位翻转就可能迫使整个传输从头开始。分块上传通过将工作单元细化为小块、使每块独立可重试且并行友好,解决了所有这些问题。
选择分块大小
分块大小是一个权衡。较小的分块在失败时恢复更快,进度粒度更细,但增加了更多HTTP开销。较大的分块摊薄了握手和TLS成本,但分块失败时浪费的带宽重传也更多。典型范围:移动端高丢包网络1 MB到5 MB,桌面网页上传5 MB到16 MB,可靠链路的服务器间传输16 MB到64 MB,以及S3多部分上传场景(1 TB文件时10,000个分块上限会迫使使用更大分块)100 MB以上。有些系统采用动态调整策略:一开始用小分块,随着连接证明其稳定性逐步扩大分块尺寸。
固定大小分块与内容定义分块
固定大小分块(比如每8 MB一块)实现简单、易于并行化,并支持精确的断点偏移量。内容定义分块(rsync和restic使用的方式)基于滚动哈希(如Rabin指纹)选取边界,使文件中间的插入操作不会导致后续所有分块边界移位。内容定义分块对备份工具的重复数据删除非常出色,但增加了复杂性和CPU开销,对于纯文件传输没有额外回报。对于上传架构,固定大小分块在简洁性上胜出,并且能简洁地映射到S3多部分分块编号或tus.io偏移量。
断点续传协议
tus.io协议(在Go的tusd、tus-js-client、Uppy等服务端框架中均有实现)使用带Upload-Offset头的HTTP PATCH来追加分块。HEAD请求返回服务器上的当前偏移量,客户端据此在网络中断后知道从哪里恢复。S3多部分上传采用不同的模型:通过InitiateMultipartUpload获取UploadId,为每个分块执行UploadPart(1开始编号),最后发送附带ETag列表的CompleteMultipartUpload请求。客户端可以通过ListParts查询已上传的分块。两种协议都能在客户端重启后保持状态,并能优雅地应对连接中断。
并行上传并发度
并行上传分块能显著提升高延迟链路的吞吐量。HTTP/1.1在浏览器中每个源限制6路并发连接;HTTP/2在单个连接上复用多个流,但仍受流量控制窗口约束。典型的上传调度器会对分块进行排队,并发分发4到8个,当服务器返回429或503时施加背压。并发度过高会触发ISP限速和中间设备的连接数限制;并发度过低则让带宽白白浪费。实测数据表明,家庭宽带使用4路并行流、千兆光纤使用8到16路并行流,是多数负载场景下的最优选择。
客户端状态与断点续传元数据
断点续传要求客户端在浏览器崩溃或笔记本关机后保留足够的状态以供恢复。IndexedDB(Web存储标准的一部分)存储上传清单,记录文件哈希值、分块总数和已成功上传的分块。以文件的SHA-256哈希作为清单的键,这样重新添加同一文件时可以从上次停止的地方继续。定期清理7天以上的过期清单以避免数据膨胀。在移动端,WKWebView(iOS)和Chrome Custom Tabs(Android)可能会在内存压力下清除IndexedDB,如果可能的话应将关键状态持久化到原生存储。
服务端分块处理
服务器需要将分块重新组装为完整文件,或者在使用S3多部分上传的情况下,将组装工作委托给S3。一个最简架构:接受每个分块的PATCH请求,以上传ID和分块索引为键写入临时Blob存储,在Redis或PostgreSQL等元数据存储中记录偏移量,CompleteMultipartUpload时进行组装或标记完成。使用对象存储(S3、Cloudflare R2、Backblaze B2)而非本地磁盘存储分块Blob,因为负载均衡后的后端节点无法共享本地状态。对废弃的上传在24到72小时后进行垃圾回收以释放存储空间。
分块级别和端到端的完整性验证
上传时对每个分块进行哈希验证。S3多部分上传的ETag是每个分块的MD5哈希(或整个对象的复合哈希)。为了更强的完整性保证,在客户端对每个分块计算SHA-256并通过请求头发送;服务器将其与分块一起存储,重新读取时可进行验证。所有分块上传完成后,计算重组文件的Merkle树根或流式哈希并返回给客户端。客户端将其与原始文件的本地哈希进行比较。任何不匹配都会触发对问题分块的重传。
加密与分块的交互
端到端加密使分块略微复杂。每个分块需要自己的nonce以避免AES-GCM中的IV重用,且分块边界必须纳入认证方案。一种典型方法:通过HKDF-SHA256从根文件加密密钥派生每个分块的专属密钥(以分块索引作为上下文信息),然后用AES-256-GCM和零值或递增的nonce加密每个分块。在AAD中包含分块索引和总分块数,防止攻击者拼接或重排分块。解密时,在释放明文之前验证所有分块均存在且顺序正确。
整合起来
生产级分块上传系统的组合:5 MB到16 MB的分块大小,tus.io或S3多部分协议,4到8路并行流,IndexedDB支持的断点续传状态,每分块SHA-256完整性校验,以及可选的带派生密钥的每分块端到端加密。HexaTransfer使用AES-256-GCM客户端分块加密配合断点续传,能在不稳定的连接上可靠地处理10 GB文件。
访问 https://hexatransfer.com — 免费,无需注册,最大10 GB。