大文件切成片分头传,断在哪一片就从哪一片重来
一个几百兆的文件,用一次请求传上去,中途只要断一次就得从头再来。网络越差,越容易卡在这一步。切成片就不会,断在哪一片,补哪一片就行,前面的不用重做。这个思路跟下载的分段取数据是一个道理,只是上传这一侧要服务端配合记账。一、为什么要切片
切片首先是让失败变得便宜。几百兆的文件,失败一次重传的成本是几分钟;切成一千片,失败一片只要补几秒。这个差别在弱网环境下非常明显。还有一个隐性好处是进度可控。按片算进度,数字是真的,用户知道还要等多久;按时间估,网络一抖就全不准了。文件类型不要只看扩展名,头部内容对不上就该拒绝。
其次是让并发成为可能。并发的用处在上行带宽充足时才成立,家用宽带上行只有几兆,分十路也是一样慢。多个分片同时上传,整体耗时取决于慢的那一路,而不是所有分片加起来的总和。前提是服务端和带宽都撑得住。并发也不是越多越好,出口带宽就那么多,路开多了,每一路都慢,用户看到的总时长并没有变短。上传的接口要单独部署,跟普通接口混在一起,一个大文件就能把整个服务拖慢。
二、片的大小怎么定
片太小,请求次数多,每个请求的握手和头部开销加起来比数据本身还大;片太大,失败一次要重传的量也多。常见的做法是让总片数落在一百到一千之间。上传之后的处理是异步的,转码、压缩这些活儿不能占着请求不放。
按文件大小动态定片更合理。小文件切几片就够,大文件把片放大到几兆,确保总片数不失控,服务端记录分片状态的表也不至于爆掉。片大小定下来之后别轻易改,改了之后老任务的续传点就对不上了。片的大小还要考虑服务端的限制,单个请求体超了网关的上限,再合理的分片也传不上去。文件大小要在入口处就挡住,等传完了才发现超限,前面的流量全白费。
三、并发和顺序
并发数要有限制。开几十路同时传,客户端的内存和网络都会吃紧,服务端也要为每一路维持一个连接。通常四到八路就够,再多效果递减。
分片本身没有顺序,但合并有顺序。每一片都带着自己的编号,合并的时候按编号拼回去,缺一片就拼不成,服务端要能明确说出缺的是哪一片。缺片的信息要准到编号,只说缺片,客户端只能全部重传,前面省下的功夫就白费了。临时文件要有人清,传到一半断掉留下的碎片,攒上几个月能把磁盘占满。
四、合并这一步
合并有两种做法:客户端传完之后发一个请求,服务端按编号依次读取再拼成一个文件;或者写入的时候就直接写到目标文件的对应偏移位置,传完即完成。
前一种实现简单,但要额外的读写;后一种省一次拷贝,但对存储的要求高。写入偏移位置的做法要确保分片大小一致,末片除外的规则要提前约定好。文件系统支持随机写就用后一种,对象存储一般只能用前一种。分片的大小要按网络状况调,片太小请求次数多,片太大失败一次重传的成本高。
五、失败与重试
重试要按分片来,别整个文件重来。重试的次数要有上限,连续失败几次就该停下来,给用户一个明确的提示,而不是无限转圈。
重试还要考虑退避。网络抖动的时候立刻重试,大概率还是失败,间隔几百毫秒再试,成功率会高一些。退避的时间可以按失败次数递增,头一次等半秒,第二次等一秒,到五六次还没成功,就该告诉用户换个网络再试。上传进度要真实,按已确认收到的字节算,别按发出去的算,不然进度条会骗人。
六、清理不能忘
传到一半放弃的文件,分片会留在服务端。要有定时任务清理超过一定时间没动静的上传任务,否则存储会被这些半成品慢慢占满。
清理的周期要跟业务对上。用户可能第二天回来接着传,清得太快会把他的进度也清掉,清得太慢又占地方。清理任务要能按任务编号查,用户来问为什么传了一半没了,得答得出来。合并分片这一步要能重入,合并失败再点一次,结果应该是一样的。
切片这件事,说白了是把一次大的失败拆成很多次小的失败。拆得合理,弱网下的体验就能好一大截。 很多细节都考虑到了,看得出来是真正懂行的人在认真分享。
页:
[1]