解读阿里云oss

摘要: oss sdk 断点续传功能使用及其相关原理

前言 
移动端现状 
随着移动端设备的硬件水平的不断提高,如今的cpu,内存等方面都大大的超过了一般的pc电脑,因此在现今的程序中,合理的使用多线程去完成一些事情是非常有必要的。 
多线程上传的好处

我有几张阿里云幸运券分享给你,用券购买或者升级阿里云相应产品会有特惠惊喜哦!把想要买的产品的幸运券都领走吧!快下手,马上就要抢光了。

进一步占满网络资源。 
进一步占满I/O资源。 
实现原理 
策略 
oss有分片上传的功能,阿里云断点续传就是基于分片上传的几个api接口进行的封装,主要由InitiateMultipartUpload,UploadPart,CompleteMultipartUpload,AbortMultipartUpload,ListParts这几个组成。 
流程 
图片描述
细节 
断点续传是一个大任务,又3部分来完成,分别是获取uploadId,分片上传,完成上传,这一整个连续的步骤统一在一个线程中进行。 
获取uploadId这块需要先对本地缓存文件进行获取,如未拿到,就会直接重新生成新的uploadId直接去进行分片上传,否则会对记录的id进行之前上传了多少片进行还原,继续原来的位置继续上传。 
分片上传部分,采用多线程并发上传机制,目前线程开启数量最多5条,根据cpu的核数进行判断,如果核数<5 会采用核数进行配置, 分片的个数最多5000。 
完成上传,对上传的part进行排序,需要按照自然顺序1~n 的顺序进行上传。 
文件校验,通过文件的md5等其他信息进行校验,分片上传中每一片也会跟服务器做md5校验。 
进度回调机制,目前进度回调算是最基础版,目前回调原理是根据每一个分片来回调的,即当分片上传成功回调一次。 
使用方式 
在本地持久保存断点记录的调用方式:

android:

1String recordDirectory = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oss_record/"; 2File recordDir = new File(recordDirectory); 3// 要保证目录存在,如果不存在则主动创建 4if (!recordDir.exists()) { 5 recordDir.mkdirs(); 6} 7// 创建断点上传请求,参数中给出断点记录文件的保存位置,需是一个文件夹的绝对路径 8ResumableUploadRequest request 9 = new ResumableUploadRequest("<bucketName>", "<objectKey>", "<uploadFilePath>", recordDirectory); 10 // 设置上传过程回调 11request.setProgressCallback(new OSSProgressCallback<ResumableUploadRequest>() { 12 @Override 13 public void onProgress(ResumableUploadRequest request 14 , long currentSize, long totalSize) { 15 Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize); 16 } 17}); 18OSSAsyncTask resumableTask = oss.asyncResumableUpload(request 19 , new OSSCompletedCallback<ResumableUploadRequest, ResumableUploadResult>() { 20 @Override 21 public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) { 22 Log.d("resumableUpload", "success!"); 23 } 24 25 @Override 26 public void onFailure(ResumableUploadRequest request, ClientException clientExcepion 27 , ServiceException serviceException) { 28 // 异常处理 29 } 30});

ios:

1// 获得UploadId进行上传,如果任务失败并且可以续传,利用同一个UploadId可以上传同一文件到同一个OSS上的存储对象 2OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new]; 3resumableUpload.bucketName = <bucketName>; 4resumableUpload.objectKey = <objectKey>; 5resumableUpload.partSize = 1024 * 1024; 6resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) { 7 NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend); 8}; 9 10resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:<your file path>]; 11NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]; 12resumableUpload.recordDirectoryPath = cachesDir;//记录断点的文件路径 13OSSTask * resumeTask = [client resumableUpload:resumableUpload]; 14[resumeTask continueWithBlock:^id(OSSTask *task) { 15 if (task.error) { 16 NSLog(@"error: %@", task.error); 17 if ([task.error.domain isEqualToString:OSSClientErrorDomain] 18 && task.error.code == OSSClientErrorCodeCannotResumeUpload) { 19 // 该任务无法续传,需要获取新的uploadId重新上传 20 } 21 } else { 22 NSLog(@"Upload file success"); 23 } 24 return nil; 25}];

性能统计 
数据分析 
android/ios 端的分片上传改为并发后的测试与之前对比,上传分片的网络请求速度 多线程 和 单线程是一样的使用时间,这个主要是取决于带宽速度, 多线程相较于单线程主要是提高了读取文件的io时间。数据如下:

1iOS 模拟器测试 2100mb大小文件 31000 part num 单线程 104.530217s 多线程 54.528591s 4100 part num 单线程 59.306880s 多线程 54.336914s 51.31g 大小文件 6100 part num 单线程 746.775666s 多线程 731.940330s 71000 part num 单线程 822.866331s 多线程 733.306236s 82000 part num 单线程 965.428122s 多线程 731.940330s 95000 part num 单线程 1205.379382s 多线程 732.982330s 10android motoXT1085 双核cpu 11100mb文件 12100 part num 单线程 70.484s 多线程 53.656s 131000 part num 单线程 104.530217s 多线程54.528591s 141.31g视频文件 15135 part num 单线程 869s 多线程 738s 161342 part num 单线程 1079.081s 多线程 732.079s

图片描述
总体来看比之前有提升,单线程随着片的个数的增加时间耗时越来越高,而多线程下,时间基本是一样的,按照目前默认配置的part size 256kb ,单线程下网络资源与I/O资源都吃满,并发下性能提高平均有30%左右(上传时间减少)

小结 
移动端下,网络资源与I/O资源一般都比较紧缺,多线程不会提高网络的总带宽:比如,在跑满某个资源下载策略分配一个连接供给带宽2000Kb/s的时候,本地单线程 能够同时吃满 2000Kb/s,这里就到达了一个峰值;但是如果某个资源连接带宽是2000Kb/s,但是单线程请求带宽 已经达到 2000Kb/s,那么就是本地网络带宽 Block了上传速度,也就是说开再多线程,再多连接也都无济于事;但,如果本地网络带宽 吃完2000Kb/s 的同时还有很多的网络资源剩余,假如还有2000Kb/s的提升空间,那么这时再建立一个连接 将这 2000Kb/s 也吃满,那么此时的速度就可以达到 4000Kb/s,这时提速很明显,I/O资源同理。

后续计划 
增加crc64编码方式进行文件正确性校验,服务端与客户端进行交互验证。 
分片上传的多线程数量改为可配置,用户可以根据自己的实际需求进行设置。 
进度回调优化,对进度的粒度进一步的细化,支持回调频率可配置等。

阅读原文

http://click.aliyun.com/m/37323/

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )