零拷貝 如何高效的通過網路傳輸檔案

2021-10-23 18:52:53 字數 2828 閱讀 4617

假如要傳輸320mb的檔案,那麼你可能會在應用程式分配32kb的記憶體空間,然後呼叫read函式從檔案中讀出32位元組,最後呼叫write函式通過網路發生出去,其流程如下圖所示。

這種方式非常低效,主要有如下的原因:

1、至少經歷了4萬次使用者態與核心態的上下文切換。因為每處理32kb的訊息,就需要一次read呼叫和一次write呼叫,每次系統呼叫都得先從使用者態切換到核心態,等核心完成任務後,再從核心態切換回使用者態。上下文切換的成本並不小,雖然一次切換僅消耗幾十納秒到幾微秒,但高併發服務會放大這類時間的消耗。

2、4萬次記憶體拷貝,對320mb檔案拷貝的位元組數也翻了4倍,到了 1280mb。因為每傳送32kb的資料,都發生了4次記憶體拷貝,第一次從磁碟拷貝到核心的pagecache中,第二次從核心的pagecache拷貝到使用者緩衝區中,第三次從使用者緩衝區拷貝到核心的socket緩衝區中,最會一次從socket緩衝區拷貝到網絡卡的環形緩衝區中。

linux核心2.1開始引入乙個叫sendfile系統呼叫,這個系統呼叫可以在核心態內把資料從核心緩衝區直接複製到套接字(socket)緩衝區內,從而可以減少上下文的切換和不必要資料的複製

#includessize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);

out_fd是寫出的檔案描述符,而且必須是乙個socket

in_fd是讀取內容的檔案描述符,必須是乙個真實的檔案, 不能是管道或socket

offset是開始讀的位置

count是將要讀取的位元組數

有了sendfile這個系統呼叫後, 傳輸檔案變為:

1. 應用程式開始讀檔案的操作

2. 應用程式發起系統呼叫, 從使用者態切換到核心態(第一次上下文切換)

3. 核心態中通過dma把資料從硬碟檔案讀取到核心pagecache

4. 在核心態中把資料從核心pagecache複製到socket的緩衝區

5. 核心態中再通過dma把資料從socket的緩衝區拷貝到網絡卡的環形緩衝區上

6. 從核心態切換到使用者態(第二次上下文切換)

流程圖如下:

從而使得320mb檔案的傳輸,上下文切換變成2次,總共需要拷貝960mb。

在核心2.4以後的版本中, linux核心對socket緩衝區描述符做了優化。把資料直接從pagecache複製到網絡卡的環形緩衝區中(這個技術叫sg-dma(the scatter-gather direct memory access),注意網絡卡也需支援)。從而避免了從"pagecache"拷貝到"socket緩衝區"的這一次拷貝。從而傳輸檔案的流程繼續簡化為

1. 應用程式開始讀檔案的操作

2. 應用程式發起系統呼叫, 從使用者態切換到核心態(第一次上下文切換)

3. 核心態中通過dma把資料從硬碟檔案讀取到核心pagecache

4. 核心態中通過dma把資料從pagecache拷貝網絡卡的環形緩衝區上

5. 從核心態切換到使用者態(第二次上下文切換)

流程圖如下:

從而使得320mb檔案的傳輸,上下文切換變成2次,總共需要拷貝640mb。

零拷貝技術不但通過減少上下文切換的次數與檔案拷貝的次數,還使得我們不用管理一次發生的位元組數。我們知道socket的傳送緩衝區大小是動態變化的,如果應用程式的緩衝區如果設定的過小,那麼上下文切換次數將會增多,但是如果設定的過大,我們呼叫write函式的時候,又不能一次全部寫完。而零拷貝技術由於傳輸檔案都在核心中進行,因此核心可以最大化的利用傳送緩衝區的大小,從而最大化的利用網路。

通過如上的技術,零拷貝可以在很大的程度上提高網路傳輸速度,通常可以提高一倍以上。

那麼有沒有什麼場景不適合使用零拷貝技術呢?當系統中存在多個應用程式讀寫小檔案並且沒有做資源隔離時,如果某個應用需要傳輸大檔案,那麼傳輸大檔案時不應該使用零拷貝技術。主要原因如下:

從上面的可以看出,核心從磁碟讀取檔案時,都會先讀取到pagecache中,根據時間區域性性原理(剛被訪問的資料在短時間內再次被訪問的概率很高)與空間區域性性原理(剛被訪問的資料的後面的資料在很短的時間內再次被訪問的概率很高),為此核心會使用lru演算法快取pagecache的資料,同時讀取磁碟的時候預讀一些資料。那麼對於大檔案,由於動輒幾個gb,第一次訪問資料的時候,再次被訪問的概率比較小。如果讀取檔案都進過pagecache那麼記憶體將很快被pagecache占用完,那麼將會觸發lru淘汰演算法,從而導致其他小檔案的快取被淘汰出記憶體,導致快取命中低效。為此在這個場景中應該使用直接io,自然也不應使用零拷貝技術。

直接 io 的應用場景並不多,主要有兩種:

1、應用程式已經實現了磁碟檔案的快取,不需要pagecache再次快取,引發額外的效能消耗。比如 mysql 等資料庫就使用直接 io;

2、高併發下傳輸大檔案,我們上文提到過,大檔案難以命中pagecache快取,又帶來額外的記憶體拷貝,同時還擠占了小檔案使用pagecache時需要的記憶體,因此,這時應該使用直接 io。

直接 io 也有一定的缺點。除了快取外,核心(io 排程演算法)會試圖快取盡量多的連續io在pagecache中,最後合併成乙個更大的io發給磁碟,這樣可以減少磁碟的定址操作;另外,核心也會預讀後續的 io 放在pagecache中,減少磁碟操作。直接 io 繞過了pagecache,所以無法享受這些效能提公升。

如何高效傳輸檔案之零拷貝

pagecache 磁碟快取記憶體 大檔案零拷貝下的問題 非同步io 直接io 總結磁碟是主機中最慢的硬體,往往是效能的瓶頸,優化它能獲得立竿見影的效果。針對磁碟的優化技術有零拷貝 直接io 非同步io等 主要目的是為了降低時延 提公升作業系統的吞吐量,圍繞著核心的磁碟快取記憶體 pagecache...

零拷貝 高效地傳輸檔案

基於使用者緩衝區傳輸檔案時,過多的記憶體拷貝與上下文切換次數會降低效能。零拷貝技術在核心中完成記憶體拷貝,天然降低了記憶體拷貝次數。它通過一次系統呼叫合併了磁碟讀取與網路傳送兩個操作,降低了上下文切換次數。尤其是,由於拷貝在核心中完成,它可以最大化使用 socket 緩衝區的可用空間,從而提高了一次...

什麼是零拷貝?一招學會高效傳輸檔案

差一點我們就擦肩而過了 有趣有用 有態度 導學問題 1.伺服器通過網路傳輸資料時,系統有幾次拷貝?2.大檔案和小檔案各有什麼傳輸特點?零拷貝 zero copy 技術指在計算機執行操作時,cpu 不需要先將資料從乙個記憶體區域複製到另乙個記憶體區域,從而可以減少上下文切換以及 cpu 的拷貝時間。某...