如何提升大容量檔案上傳效能

禧子發表於2021-06-17

背景

618壓測過程中,涉及大規格的引數化檔案上傳平臺,由於檔案過大超過2G,在平臺上傳過程中經常失敗,超時,重試也要等老半天,這就會造成人力資源等待影響工作效率。那麼應該怎麼做才能快速上傳,如何提高檔案上傳效能以及做到就算失敗了再次重試也能從上次中斷的地方繼續上傳提升系統的容錯能力呢 ?我學習整理了一些優化思路,在此分享給大家,請君看下文分解~~~

 

從業務流程上優化

為提升大檔案上傳效率和容錯性,從流程上可實現3個功能步驟。

  • 大檔案分片上傳。
  • 支援斷點續傳。
  • 上傳進度展示。

從系統底層上優化

總思路原則

降時延,提併發

  1. 減少磁碟的工作量,如pagecache技術(磁碟快取記憶體)。
  2. 減少CPU的工作量,如直接IO技術。
  1. 提高記憶體的利用率,如零拷貝技術。

 

詳細解析

要優化檔案上傳效能,必須先了解伺服器檔案上傳的過程。

過程

傳送檔案上傳請求後,首先磁碟讀取檔案,然後通過網路協議傳送給客戶端。

客戶端請求從磁碟找到檔案位置,然後從磁碟把部分檔案(切分後)讀入緩衝區,然後通過網路把資料傳送給客戶端,如下圖:

問題

1.上下文切換

一次收發過程涉及到4次使用者態和核心態的上下文切換,沒處理緩衝區大小的資料需要一次read呼叫和一次write呼叫,每次呼叫都需要從使用者態切換到核心態。然後等核心態完成任務後,再切換回使用者態,如果檔案大,分片較多,讀取次數比較多,上下文切換的成本不容小覷。

 

2.多次記憶體拷貝

磁碟-》pagecache

pagecache->使用者緩衝區

使用者緩衝區->socket緩衝區

socket緩衝區->網路卡

多次記憶體拷貝,消耗過多的CPU資源,降低系統併發能力,表現為CPU系統態佔用過高

 

解決思路方案

零拷貝技術

降低上下文切換

首先讀取磁碟檔案的上下文切換是一定會有的,因為讀取磁碟和操作網路卡都是由作業系統核心完成,所以我們再執行read或write這種系統呼叫時,一定會經過2次上下文切換:先從使用者態切換到核心態,當核心態任務完成後,再切換回使用者態交由程式程式碼執行。所以想要降低上下文切換就需減少系統呼叫次數。解決辦法是把read和write兩次系統呼叫合併成一次,在核心態中完成磁碟與網路卡的資料交換操作。

減少記憶體拷貝次數

一次收發過程有兩次與物理裝置相關的記憶體拷貝是必不可少的:1.把磁碟的資料拷貝到記憶體,2.把記憶體的資料拷貝到網路卡,而使用者緩衝區相關的拷貝則不是必須的,故可以在核心讀取檔案後,直接把pagecache中的資料拷貝socket緩衝區,這樣就只有2次上下文切換和3次記憶體拷貝,如果網路卡支援SG-DMA技術,還可以把拷貝到socket緩衝區的步驟省略,如下圖:

 

 

PageCache磁碟快取記憶體技術

根據時間區域性性原理,剛被訪問到的資料在短時間被再次訪問的概率高,通常將最近訪問的資料放到pagecache中,當空間不足時根據LRU演算法淘汰最久未被訪問的資料。

pagecache提供預讀功能,但不適合傳輸大檔案,因為大檔案容易把pagecache佔滿,而且由於檔案過大,檔案中某一部分的資料被再次訪問的概率低,這會導致大檔案在pagecache中沒有享受到快取的優勢。

非同步IO&直接IO技術

非同步IO可以把讀操作分為兩個部分,前部向核心發起讀請求,但不用等待資料就位就返回,然後可以繼續處理其他任務,當核心把磁碟中的資料拷貝到程式緩衝區後,會通知程式去處理資料,非同步IO是不會阻塞使用者程式的,能提升併發操作。

對於磁碟,非同步IO只支援直接IO,即應用程式繞過pagecache,不經過核心快取區,直接訪問磁碟中的資料,從而減少了核心快取與使用者程式之間的資料拷貝。

因為直接IO不適用pagecache快取,所以享受不到核心針對pagecache做的一些優化,這是不足之處。故直接IO適應的應用場景:1.應用程式已經自己實現了磁碟檔案的快取,不需要pagecache再次進行快取,引發額外的效能消耗;2.高併發下傳輸大檔案,因為大檔案難以命中pagecache快取,又會影響其他熱點小檔案快取。

 

方法論

從系統層面的優化思路上看,大檔案交給非同步IO和直接IO技術處理,小檔案交給零拷貝技術處理。

 

相關文章