SpringCloud⼤⽂件分⽚断点上传实现原理
1背景
⽤户本地有⼀份txt或者csv⽂件,⽆论是从业务数据库导出、还是其他途径获取,当需要使⽤蚂蚁的⼤数据分析⼯具进⾏数据加⼯、挖掘和共创应⽤的时候,⾸先要将本地⽂件上传⾄ODPS,普通的⼩⽂件通过浏览器上传⾄服务器,做⼀层中转便可以实现,但当这份⽂件⾮常⼤到了10GB级别,我们就需要思考另⼀种形式的技术⽅案了,也就是本⽂要阐述的⽅案。
技术要求主要有以下⼏⽅⾯:
⽀持超⼤数据量、10G级别以上大文件发送
稳定性:除⽹络异常情况100%成功
准确性:数据⽆丢失,读写准确性100%
效率:1G⽂件分钟级、10G⽂件⼩时级
体验:实时进度感知、⽹络异常断点续传、定制字符特殊处理
2⽂件上传选型
⽂件上传⾄ODPS基本思路是先⽂件上传⾄某中转区域存储,然后同步⾄ODPS,根据存储介质可以分为两类,⼀类是应⽤服务器磁盘,另⼀类类是中间介质,OSS作为阿⾥云推荐的海量、安全低成本云存储服务,并且有丰富的API⽀持,成为中间介质的⾸选。⽽⽂件上传⾄OSS⼜分为web直传和sdk上传两种⽅案,因此上传⽅案有如下三种,详细优缺点对⽐如下:
蚂蚁的⽂本上传功能演进过程中对第⼀种、第⼆种⽅案均有实践,缺点⽐较明显,如上表所述,不满⾜业务需求,因此⼤⽂件上传终极⽅案是⽅案三。
3整体⽅案
以下是⽅案三的整体过程⽰意图。
请求步骤如下:
⽤户向应⽤服务器取到上传policy和回调设置。
应⽤服务器返回上传policy和回调。
⽤户直接向OSS发送⽂件上传请求。
等⽂件数据上传完,OSS给⽤户Response前,OSS会根据⽤户的回调设置,请求⽤户的服务器。如果应⽤服务器返回成功,那么就返回⽤户成功,如果应⽤服务器返回失败,那么OSS也返回给⽤户失败。这样确保了⽤户上传成功,应⽤服务器已经收到通知了。
应⽤服务器给OSS返回。
OSS将应⽤服务器返回的内容返回给⽤户。
启动后台同步引擎执⾏oss到odps的数据同步。
同步实时进度返回返回给应⽤服务器,同时展⽰给⽤户。
4技术⽅案
4.1上传
OSS提供了丰富的SDK,有简单上传、表单上传、断点续传等等,对于超⼤⽂件提供的上传功能建议采⽤断点续传⽅式,优点是可以对⼤⽂件并⾏分⽚上传,利⽤OSS的并⾏处理能⼒,中间暂停也可以从当前位置继续上传,⽹络环境影响可以降到最低。
OSS⽂件下载同样也有多种⽅式,普通下载、流式下载、断点续传下载、范围下载等等,若直接下载到本地同样建议断点续传下载,但我们的需求并不仅仅是下载⽂件本地存储,⽽是读取⽂件做数据从OSS到ODPS的同步,因此不做中间存储,直接边读变写,⼀⽅⾯采⽤OSS流式读取,⼀⽅⾯ODPS tunnel上传,⽤多线程读写⽅式提⾼同步速率。
4.3两阶段数据转移
⽂件从本地到ODPS可以分为两个阶段,第⼀阶段前端分⽚断点续传将本地⽂件上传⾄OSS,第⼆阶段后端流式读写将数据从OSS同步⾄ODPS,如下图所⽰:
涉及技术点:
4.3.1前端,js sdk带STS token 安全上传
在需要上传的⽂件较⼤时,可以通过multipartUpload接⼝进⾏分⽚上传。分⽚上传的好处是将⼀个⼤请求分成多个⼩请求来执⾏,这样当其中⼀些请求失败后,不需要重新上传整个⽂件,⽽只需要上传
失败的分⽚就可以了。⼀般对于⼤于100MB的⽂件,建议采⽤分⽚上传的⽅法,每次进⾏分⽚上传都建议重新new⼀个新的OSS实例。
阿⾥云分⽚上传流程主要会调⽤3个api,包含
InitiateMultipartUpload, 分⽚任务初始化接⼝。
UploadPart,单独的分⽚上传接⼝。
CompleteMultipartUpload, 分⽚上传完成后任务完成接⼝
临时访问凭证是通过阿⾥云Security Token Service(STS)来实现授权的⼀种⽅式。其实现请参见STS Java SDK。临时访问凭证的流程如下:
客户端向服务器端发起获得授权的请求。服务器端先验证客户端的合法性。如果是合法客户端,那么服务器端会使⽤⾃⼰的AccessKey来向STS发起⼀个请求授权的请求,具体可以参考访问控制。
服务器端获取临时凭证之后返回给客户端。
客户端使⽤获取的临时凭证来发起向OSS的上传请求,更详细的请求构造可以参考临时授权访问。客户端可以缓存该凭证⽤来上传,直到凭证失效再向服务器端请求新的凭证。
4.3.2后端,多线程流式读写
OSS端:如果要下载的⽂件太⼤,或者⼀次性下载耗时太长,可以多线程流式下载,⼀次处理部分内容,直到完成⽂件的下载。
ODPS端:tunnel sdk对OSS流式数据直接写⼊,⼀次完整的数据写⼊流程通常包括以下步骤:
先对数据进⾏划分;
为每个数据块指定 block id,即调⽤ openRecordWriter(id);
然后⽤⼀个或多个线程分别将这些 block 上传上去, 并在某个 block 上传失败以后,需要对整个 block 进⾏重传;
在所有 block 都上传以后,向服务端提供上传成功的 blockid list 进⾏校验,即调⽤ sessionmit([1,2,3,…])
⽽由于服务端对block管理,连接超时等的⼀些限制,上传过程逻辑变得⽐较复杂,为了简化上传过程,SDK提供了更⾼级的⼀种RecordWriter——TunnelBufferWriter。
5总结
实测结果显⽰,本⽂的上传⽅案实现了第⼀节提出的⼏点技术要求,如下:
⽀持超⼤数据量、10G级别以上没有任何压⼒,主要是前端在分⽚上传设置好分⽚限额即可(最⼤10000⽚,每⽚最⼤
100G),⽬前设置每⽚1M满⾜10G需求。
稳定性:实测观察⽹络异常情况较少,⽂件内容正常情况下100%成功。
准确性:实测数据⽆丢失,读写准确性100%。
效率:办公⽹带宽1.5M/s的情况下1G⽂件分钟级、10G⽂件⼩时级,实际速度视⽤户端的当前⽹络带宽变化。
体验:实时进度感知、⽹络异常断点续传、定制字符特殊处理等⾼级功能可以提升⽤户体验。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。