Linux 中的零拷貝技術,第 1 部分

概述
黃 曉晨, 軟件工程師, IBM
馮 瑞, 軟件工程師, IBM


簡介: 
本系列由兩篇文章組成,介紹了當前用於 Linux 操作系統上的幾種零拷貝技術,簡單描述了各種零拷貝技術的實現,以及它們的特點和適用場景。本文是本系列文章的第一部分,主要是介紹一些零拷貝技術的相關背景知識,簡要概述了 Linux 爲什麼需要零拷貝技術以及 Linux 中都有哪幾種零拷貝技術。


引言
傳統的 Linux 操作系統的標準 I/O 接口是基於數據拷貝操作的,即 I/O 操作會導致數據在操作系統內核地址空間的緩衝區和應用程序地址空間定義的緩衝區之間進行傳輸。這樣做最大的好處是可以減少磁盤 I/O 的操作,因爲如果所請求的數據已經存放在操作系統的高速緩衝存儲器中,那麼就不需要再進行實際的物理磁盤 I/O 操作。但是數據傳輸過程中的數據拷貝操作卻導致了極大的 CPU 開銷,限制了操作系統有效進行數據傳輸操作的能力。
零拷貝( zero-copy )這種技術可以有效地改善數據傳輸的性能,在內核驅動程序(比如網絡堆棧或者磁盤存儲驅動程序)處理 I/O 數據的時候,零拷貝技術可以在某種程度上減少甚至完全避免不必要 CPU 數據拷貝操作。現代的 CPU 和存儲體系結構提供了很多特徵可以有效地實現零拷貝技術,但是因爲存儲體系結構非常複雜,而且網絡協議棧有時需要對數據進行必要的處理,所以零拷貝技術有可能會產生很多負面的影響,甚至會導致零拷貝技術自身的優點完全喪失。


爲什麼需要零拷貝技術
如今,很多網絡服務器都是基於客戶端 - 服務器這一模型的。在這種模型中,客戶端向服務器端請求數據或者服務;服務器端則需要響應客戶端發出的請求,併爲客戶端提供它所需要的數據。隨着網絡服務的逐漸普及,video 這類應用程序發展迅速。當今的計算機系統已經具備足夠的能力去處理 video 這類應用程序對客戶端所造成的重負荷,但是對於服務器端來說,它應付由 video 這類應用程序引起的網絡通信量就顯得捉襟見肘了。而且,客戶端的數量增長迅速,那麼服務器端就更容易成爲性能瓶頸。而對於負荷很重的服務器來說,操作系統通常都是引起性能瓶頸的罪魁禍首。舉個例子來說,當數據“寫”操作或者數據“發送”操作的系統調用發出時,操作系統通常都會將數據從應用程序地址空間的緩衝區拷貝到操作系統內核的緩衝區中去。操作系統這樣做的好處是接口簡單,但是卻在很大程度上損失了系統性能,因爲這種數據拷貝操作不單需要佔用 CPU 時間片,同時也需要佔用額外的內存帶寬。
一般來說,客戶端通過網絡接口卡向服務器端發送請求,操作系統將這些客戶端的請求傳遞給服務器端應用程序,服務器端應用程序會處理這些請求,請求處理完成以後,操作系統還需要將處理得到的結果通過網絡適配器傳遞回去。
下邊這一小節會跟讀者簡單介紹一下傳統的服務器是如何進行數據傳輸的,以及這種數據傳輸的處理過程存在哪些問題有可能會造成服務器的性能損失。
Linux  中傳統服務器進行數據傳輸的流程
Linux  中傳統的 I/O 操作是一種緩衝 I/O,I/O 過程中產生的數據傳輸通常需要在緩衝區中進行多次的拷貝操作。一般來說,在傳輸數據的時候,用戶應用程序需要分配一塊大小合適的緩衝區用來存放需要傳輸的數據。應用程序從文件中讀取一塊數據,然後把這塊數據通過網絡發送到接收端去。用戶應用程序只是需要調用兩個系統調用 read() 和 write() 就可以完成這個數據傳輸操作,應用程序並不知曉在這個數據傳輸的過程中操作系統所做的數據拷貝操作。對於 Linux 操作系統來說,基於數據排序或者校驗等各方面因素的考慮,操作系統內核會在處理數據傳輸的過程中進行多次拷貝操作。在某些情況下,這些數據拷貝操作會極大地降低數據傳輸的性能。
當應用程序需要訪問某塊數據的時候,操作系統內核會先檢查這塊數據是不是因爲前一次對相同文件的訪問而已經被存放在操作系統內核地址空間的緩衝區內,如果在內核緩衝區中找不到這塊數據,Linux 操作系統內核會先將這塊數據從磁盤讀出來放到操作系統內核的緩衝區裏去。如果這個數據讀取操作是由 DMA 完成的,那麼在 DMA 進行數據讀取的這一過程中,CPU 只是需要進行緩衝區管理,以及創建和處理 DMA ,除此之外,CPU 不需要再做更多的事情,DMA 執行完數據讀取操作之後,會通知操作系統做進一步的處理。Linux 操作系統會根據 read() 系統調用指定的應用程序地址空間的地址,把這塊數據存放到請求這塊數據的應用程序的地址空間中去,在接下來的處理過程中,操作系統需要將數據再一次從用戶應用程序地址空間的緩衝區拷貝到與網絡堆棧相關的內核緩衝區中去,這個過程也是需要佔用 CPU 的。數據拷貝操作結束以後,數據會被打包,然後發送到網絡接口卡上去。在數據傳輸的過程中,應用程序可以先返回進而執行其他的操作。之後,在調用 write() 系統調用的時候,用戶應用程序緩衝區中的數據內容可以被安全的丟棄或者更改,因爲操作系統已經在內核緩衝區中保留了一份數據拷貝,當數據被成功傳送到硬件上之後,這份數據拷貝就可以被丟棄。

從上面的描述可以看出,在這種傳統的數據傳輸過程中,數據至少發生了四次拷貝操作,即便是使用了 DMA 來進行與硬件的通訊,CPU 仍然需要訪問數據兩次。在 read() 讀數據的過程中,數據並不是直接來自於硬盤,而是必須先經過操作系統的文件系統層。在 write() 寫數據的過程中,爲了和要傳輸的數據包的大小相吻合,數據必須要先被分割成塊,而且還要預先考慮包頭,並且要進行數據校驗和操作。


圖 1. 傳統使用 read 和 write 系統調用的數據傳輸



零拷貝(zero copy)技術概述
什麼是零拷貝?

簡單一點來說,零拷貝就是一種避免 CPU 將數據從一塊存儲拷貝到另外一塊存儲的技術。針對操作系統中的設備驅動程序、文件系統以及網絡協議堆棧而出現的各種零拷貝技術極大地提升了特定應用程序的性能,並且使得這些應用程序可以更加有效地利用系統資源。這種性能的提升就是通過在數據拷貝進行的同時,允許 CPU 執行其他的任務來實現的。零拷貝技術可以減少數據拷貝和共享總線操作的次數,消除傳輸數據在存儲器之間不必要的中間拷貝次數,從而有效地提高數據傳輸效率。而且,零拷貝技術減少了用戶應用程序地址空間和操作系統內核地址空間之間因爲上下文切換而帶來的開銷。進行大量的數據拷貝操作其實是一件簡單的任務,從操作系統的角度來說,如果 CPU 一直被佔用着去執行這項簡單的任務,那麼這將會是很浪費資源的;如果有其他比較簡單的系統部件可以代勞這件事情,從而使得 CPU 解脫出來可以做別的事情,那麼系統資源的利用則會更加有效。綜上所述,零拷貝技術的目標可以概括如下:
避免數據拷貝

  • 避免操作系統內核緩衝區之間進行數據拷貝操作。
  • 避免操作系統內核和用戶應用程序地址空間這兩者之間進行數據拷貝操作。
  • 用戶應用程序可以避開操作系統直接訪問硬件存儲。
  • 數據傳輸儘量讓 DMA 來做。

將多種操作結合在一起

  • 避免不必要的系統調用和上下文切換。
  • 需要拷貝的數據可以先被緩存起來。
  • 對數據進行處理儘量讓硬件來做。

前文提到過,對於高速網絡來說,零拷貝技術是非常重要的。這是因爲高速網絡的網絡鏈接能力與 CPU 的處理能力接近,甚至會超過 CPU 的處理能力。如果是這樣的話,那麼 CPU 就有可能需要花費幾乎所有的時間去拷貝要傳輸的數據,而沒有能力再去做別的事情,這就產生了性能瓶頸,限制了通訊速率,從而降低了網絡鏈接的能力。一般來說,一個 CPU 時鐘週期可以處理一位的數據。舉例來說,一個 1 GHz 的處理器可以對 1Gbit/s 的網絡鏈接進行傳統的數據拷貝操作,但是如果是 10 Gbit/s 的網絡,那麼對於相同的處理器來說,零拷貝技術就變得非常重要了。對於超過 1 Gbit/s 的網絡鏈接來說,零拷貝技術在超級計算機集羣以及大型的商業數據中心中都有所應用。然而,隨着信息技術的發展,1 Gbit/s,10 Gbit/s 以及 100 Gbit/s 的網絡會越來越普及,那麼零拷貝技術也會變得越來越普及,這是因爲網絡鏈接的處理能力比 CPU 的處理能力的增長要快得多。傳統的數據拷貝受限於傳統的操作系統或者通信協議,這就限制了數據傳輸性能。零拷貝技術通過減少數據拷貝次數,簡化協議處理的層次,在應用程序和網絡之間提供更快的數據傳輸方法,從而可以有效地降低通信延遲,提高網絡吞吐率。零拷貝技術是實現主機或者路由器等設備高速網絡接口的主要技術之一。
現代的 CPU 和存儲體系結構提供了很多相關的功能來減少或避免 I/O 操作過程中產生的不必要的 CPU 數據拷貝操作,但是,CPU 和存儲體系結構的這種優勢經常被過高估計。存儲體系結構的複雜性以及網絡協議中必需的數據傳輸可能會產生問題,有時甚至會導致零拷貝這種技術的優點完全喪失。在下一章中,我們會介紹幾種 Linux 操作系統中出現的零拷貝技術,簡單描述一下它們的實現方法,並對它們的弱點進行分析。
零拷貝技術分類
零拷貝技術的發展很多樣化,現有的零拷貝技術種類也非常多,而當前並沒有一個適合於所有場景的零拷貝技術的出現。對於 Linux 來說,現存的零拷貝技術也比較多,這些零拷貝技術大部分存在於不同的 Linux 內核版本,有些舊的技術在不同的 Linux 內核版本間得到了很大的發展或者已經漸漸被新的技術所代替。本文針對這些零拷貝技術所適用的不同場景對它們進行了劃分。概括起來,Linux 中的零拷貝技術主要有下面這幾種:

  • 直接 I/O:對於這種數據傳輸方式來說,應用程序可以直接訪問硬件存儲,操作系統內核只是輔助數據傳輸:這類零拷貝技術針對的是操作系統內核並不需要對數據進行直接處理的情況,數據可以在應用程序地址空間的緩衝區和磁盤之間直接進行傳輸,完全不需要 Linux 操作系統內核提供的頁緩存的支持。
  • 在數據傳輸的過程中,避免數據在操作系統內核地址空間的緩衝區和用戶應用程序地址空間的緩衝區之間進行拷貝。有的時候,應用程序在數據進行傳輸的過程中不需要對數據進行訪問,那麼,將數據從 Linux 的頁緩存拷貝到用戶進程的緩衝區中就可以完全避免,傳輸的數據在頁緩存中就可以得到處理。在某些特殊的情況下,這種零拷貝技術可以獲得較好的性能。Linux 中提供類似的系統調用主要有 mmap(),sendfile() 以及 splice()。
  • 對數據在 Linux 的頁緩存和用戶進程的緩衝區之間的傳輸過程進行優化。該零拷貝技術側重於靈活地處理數據在用戶進程的緩衝區和操作系統的頁緩存之間的拷貝操作。這種方法延續了傳統的通信方式,但是更加靈活。在  Linux  中,該方法主要利用了寫時複製技術。

前兩類方法的目的主要是爲了避免應用程序地址空間和操作系統內核地址空間這兩者之間的緩衝區拷貝操作。這兩類零拷貝技術通常適用在某些特殊的情況下,比如要傳送的數據不需要經過操作系統內核的處理或者不需要經過應用程序的處理。第三類方法則繼承了傳統的應用程序地址空間和操作系統內核地址空間之間數據傳輸的概念,進而針對數據傳輸本身進行優化。我們知道,硬件和軟件之間的數據傳輸可以通過使用 DMA 來進行,DMA  進行數據傳輸的過程中幾乎不需要  CPU  參與,這樣就可以把 CPU 解放出來去做更多其他的事情,但是當數據需要在用戶地址空間的緩衝區和  Linux  操作系統內核的頁緩存之間進行傳輸的時候,並沒有類似  DMA  這種工具可以使用,CPU  需要全程參與到這種數據拷貝操作中,所以這第三類方法的目的是可以有效地改善數據在用戶地址空間和操作系統內核地址空間之間傳遞的效率。

總結
本系列文章介紹了 Linux 中的零拷貝技術,本文是其中的第一部分,介紹了零拷貝技術的基本概念,Linux 爲什麼需要零拷貝這種技術以及簡要概述了 Linux 中都存在哪些零拷貝技術這樣一些基本背景知識。我們將在本系列文章的第二部分內容中詳細介紹本文提到的 Linux 中的幾種零拷貝技術。


原文:http://www.ibm.com/developerworks/cn/linux/l-cn-zerocopy1/index.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章