腾讯云 COS 上传
端内文件上传, 之前各个业务都是自己写的上传, 有的是用 PUT 请求, 有的是放在业务POST请求的 body 中, 对于批量图片上传由于担心上传长时间抢占带宽设置了30 秒强制超时, 对于大文件比如视频上传则是业务自己实现了分片上传, 上传逻辑复杂, 业务自己实现细节繁多, 成功率也不高. 后来切换到了腾讯云的 COS 上传, 图片上传成功率由97.5% 上升至 99.13%, 视频上传成功率由 92.88% 上升到 96.92%. 同时将 COS上传 封装为通用的上传逻辑, 输入支持磁盘文件/内存对象的上传, 输出支持进度以及结果回调, 并额外支持了秒传/断点续传/分片上传/批量上传/取消上传/秘钥小颗粒权限以及自动续期/容灾/全球加速/IPv6/结果统计/安全打击/灵活扩容/拓展灵活(如图片格式/尺寸/视频入库...)等能力.
上传架构图总览

模块设计
流程图注释:
四个虚线框 是四个模块
- UploadPackage: 处理批量上传
- UploadTask: 做单个文件的上传
- UploadManager: 是为了保留全局信息 比正在上传文件列表, 以及管理续传信息, 容灾时全局小黑屋等.
- UploadService: 为 UploadPackage 处理秘钥逻辑, 映射关系为 bussID+BucketKey 对应一个 UploadService
上传能力支持
秒传
使用文件 sha1 作为秒传依据.
iOS 处理 sha1 以及 md5 时间对比如下:
| sha1 | md5 | |
|---|---|---|
| 视频15s | 0.02s | 0.026s | 
| 视频14min | 0.88s | 2.15s | 
| 视频6.5小时, 文件大小 2.54G | 2.12s | 5.51s | 
续传
客户端保留上传过程中的 uploadID 即可uploadID 需要与 桶 Bucket 以及文件 sha1 绑定, 换桶的时候, 原有桶对应的 uploadID 就无用了, 上传失败时候保留 uploadID, 方便后续续传, 上传成功再清空uploadID (只是为了清理存储, 没有特殊意义)
桶的定义如下 :
| 1 | struct BucketInfo{ | 
续传信息需要持久化保存
秘钥续期
虽然后台会下发秘钥过期时间, 但是由于客户端时间可能不准, 所以客户端无需自行判定过期, COS SDK 会给过期回调
SDK 遇到秘钥续期的时候会调用下面方法:
| 1 | /** | 
在此回调续期 调用 InitUpload 只用回包的秘钥字段即可.
秘钥要注意的是同一批次请求的秘钥是可以共用的, 但是不同批次的秘钥不能共用, 不同批次的秘钥续期也得分开续期,
比如 第一次上传 ABCD, 后台下发秘钥 1, 第二次上传EFG, 后台下发秘钥 2, 那么 ABCD 遇到秘钥过期的时候, 只更新一次 秘钥 1 即可, EFG 秘钥过期就不能用秘钥 1, 而是得自行更新秘钥 2.
容灾
业务可以配置主备存储桶, 后台下发多个桶信息; 主桶选择 广州地点
切换备桶的时机. sdk可设置上传进度回调,记录当前进度
失败时如果进度为0, 切换备桶重试
失败时如果进度>0, 不用切换桶, 直接失败, 业务重试之后,可触发断点续传
如果没网络直接报错,不必切换桶
容灾时候如果还有桶可用, 当前桶关15分钟小黑屋, 使用下一个桶进行重试, 如果再无可用桶, 就不用关小黑屋, 直接失败即可.
开始上传的时候, 所有的桶都进了小黑屋的话, 从第一个桶重试, 所有桶重试完直接失败, 无需再关小黑屋.
全球加速
配置全球加速节点, 放在下发列表靠后位置即可
IPv6
分片上传
- 文件小于 1M, 直接用 PUT请求上传即可,
- 大于 1M, 先对数据分片, 分片大小为 1M.
灵活扩容
上传api 有qps 限制, 可以配置多个桶解决