解讀阿里雲oss-android/ios-sdk 斷點續傳(多線程)

摘要:
oss sdk 斷點續傳功能使用及其相關原理

前言

  • 移動端現狀
    隨着移動端設備的硬件水平的不斷提升,現在的cpu,內存等方面都大大的超過了通常的pc電腦,所以在現今的程序中,合理的使用多線程去完成一些事情是很是有必要的。
  • 多線程上傳的好處android

    1. 進一步佔滿網絡資源。
    2. 進一步佔滿I/O資源。

實現原理

  • 策略
    oss有分片上傳的功能,阿里雲斷點續傳就是基於分片上傳的幾個api接口進行的封裝,主要由InitiateMultipartUpload,UploadPart,CompleteMultipartUpload,AbortMultipartUpload,ListParts這幾個組成。
  • 流程
    _
  • 細節
  1. 斷點續傳是一個大任務,又3部分來完成,分別是獲取uploadId,分片上傳,完成上傳,這一整個連續的步驟統一在一個線程中進行。
  2. 獲取uploadId這塊須要先對本地緩存文件進行獲取,如未拿到,就會直接從新生成新的uploadId直接去進行分片上傳,不然會對記錄的id進行以前上傳了多少片進行還原,繼續原來的位置繼續上傳。
  3. 分片上傳部分,採用多線程併發上傳機制,目前線程開啓數量最多5條,根據cpu的核數進行判斷,若是核數<5 會採用核數進行配置, 分片的個數最多5000。
  4. 完成上傳,對上傳的part進行排序,須要按照天然順序1~n 的順序進行上傳。
  5. 文件校驗,經過文件的md5等其餘信息進行校驗,分片上傳中每一片也會跟服務器作md5校驗。
  6. 進度回調機制,目前進度回調算是最基礎版,目前回調原理是根據每個分片來回調的,即當分片上傳成功回調一次。

使用方式

在本地持久保存斷點記錄的調用方式:ios

android:api

String recordDirectory = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oss_record/";
File recordDir = new File(recordDirectory);
// 要保證目錄存在,若是不存在則主動建立
if (!recordDir.exists()) {
    recordDir.mkdirs();
}
// 建立斷點上傳請求,參數中給出斷點記錄文件的保存位置,需是一個文件夾的絕對路徑
ResumableUploadRequest request 
    = new ResumableUploadRequest("<bucketName>", "<objectKey>", "<uploadFilePath>", recordDirectory);
    // 設置上傳過程回調
request.setProgressCallback(new OSSProgressCallback<ResumableUploadRequest>() {
    @Override
    public void onProgress(ResumableUploadRequest request
              , long currentSize, long totalSize) {
         Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize);
     }
});
OSSAsyncTask resumableTask = oss.asyncResumableUpload(request
    , new OSSCompletedCallback<ResumableUploadRequest, ResumableUploadResult>() {
    @Override
    public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
        Log.d("resumableUpload", "success!");
    }
    
    @Override
    public void onFailure(ResumableUploadRequest request, ClientException clientExcepion
        , ServiceException serviceException) {
           // 異常處理
    }
});複製代碼

ios:緩存

// 得到UploadId進行上傳,若是任務失敗而且能夠續傳,利用同一個UploadId能夠上傳同一文件到同一個OSS上的存儲對象
OSSResumableUploadRequest * resumableUpload = [OSSResumableUploadRequest new];
resumableUpload.bucketName = <bucketName>;
resumableUpload.objectKey = <objectKey>;
resumableUpload.partSize = 1024 * 1024;
resumableUpload.uploadProgress = ^(int64_t bytesSent, int64_t totalByteSent, int64_t totalBytesExpectedToSend) {
    NSLog(@"%lld, %lld, %lld", bytesSent, totalByteSent, totalBytesExpectedToSend);
};
    
resumableUpload.uploadingFileURL = [NSURL fileURLWithPath:<your file path>];
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
resumableUpload.recordDirectoryPath = cachesDir;//記錄斷點的文件路徑
OSSTask * resumeTask = [client resumableUpload:resumableUpload];
[resumeTask continueWithBlock:^id(OSSTask *task) {
    if (task.error) {
       NSLog(@"error: %@", task.error);
       if ([task.error.domain isEqualToString:OSSClientErrorDomain]
         && task.error.code == OSSClientErrorCodeCannotResumeUpload) {
           // 該任務沒法續傳,須要獲取新的uploadId從新上傳
       }
     } else {
         NSLog(@"Upload file success");
     }
     return nil;
}];複製代碼

性能統計

數據分析
android/ios 端的分片上傳改成併發後的測試與以前對比,上傳分片的網絡請求速度 多線程 和 單線程是同樣的使用時間,這個主要是取決於帶寬速度, 多線程相較於單線程主要是提升了讀取文件的io時間。數據以下:bash

iOS 模擬器測試  
100mb大小文件
1000 part  num  單線程  104.530217s  多線程  54.528591s
100  part  num  單線程  59.306880s  多線程  54.336914s
1.31g 大小文件
100 part  num  單線程  746.775666s  多線程  731.940330s
1000 part  num  單線程  822.866331s  多線程  733.306236s
2000 part  num  單線程  965.428122s  多線程  731.940330s
5000 part  num  單線程  1205.379382s  多線程  732.982330s
android motoXT1085 雙核cpu
100mb文件
100 part  num  單線程  70.484s  多線程   53.656s
1000 part num  單線程 104.530217s  多線程54.528591s
1.31g視頻文件
135  part num  單線程  869s  多線程  738s
1342 part num  單線程   1079.081s  多線程 732.079s複製代碼

DingTalk20171201110529
整體來看比以前有提高,單線程隨着片的個數的增長時間耗時愈來愈高,而多線程下,時間基本是同樣的,按照目前默認配置的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編碼方式進行文件正確性校驗,服務端與客戶端進行交互驗證。
  • 分片上傳的多線程數量改成可配置,用戶能夠根據本身的實際需求進行設置。
  • 進度回調優化,對進度的粒度進一步的細化,支持回調頻率可配置等。
相關文章
相關標籤/搜索