傳統的 Linux 操做系統的標準 I/O 接口是基於數據拷貝操做的,即 I/O 操做會致使數據在操做系統內核地址空間的緩衝區和應用程序地址空間定義的緩衝區之間進行傳輸。這樣作最大的好處是能夠減小磁盤 I/O 的操做,由於若是所請求的數據已經存放在操做系統的高速緩衝存儲器中,那麼就不須要再進行實際的物理磁盤 I/O 操做。可是數據傳輸過程當中的數據拷貝操做卻致使了極大的 CPU 開銷,限制了操做系統有效進行數據傳輸操做的能力。緩存
零拷貝( zero-copy )這種技術能夠有效地改善數據傳輸的性能,在內核驅動程序(好比網絡堆棧或者磁盤存儲驅動程序)處理 I/O 數據的時候,零拷貝技術能夠在某種程度上減小甚至徹底避免沒必要要 CPU 數據拷貝操做。現代的 CPU 和存儲體系結構提供了不少特徵能夠有效地實現零拷貝技術,可是由於存儲體系結構很是複雜,並且網絡協議棧有時須要對數據進行必要的處理,因此零拷貝技術有可能會產生不少負面的影響,甚至會致使零拷貝技術自身的優勢徹底喪失。安全
現在,不少網絡服務器都是基於客戶端 - 服務器這一模型的。在這種模型中,客戶端向服務器端請求數據或者服務;服務器端則須要響應客戶端發出的請求,併爲客戶端提供它所須要的數據。隨着網絡服務的逐漸普及,video 這類應用程序發展迅速。當今的計算機系統已經具有足夠的能力去處理 video 這類應用程序對客戶端所形成的重負荷,可是對於服務器端來講,它應付由 video 這類應用程序引發的網絡通訊量就顯得捉襟見肘了。並且,客戶端的數量增加迅速,那麼服務器端就更容易成爲性能瓶頸。而對於負荷很重的服務器來講,操做系統一般都是引發性能瓶頸的罪魁禍首。舉個例子來講,當數據「寫」操做或者數據「發送」操做的系統調用發出時,操做系統一般都會將數據從應用程序地址空間的緩衝區拷貝到操做系統內核的緩衝區中去。操做系統這樣作的好處是接口簡單,可是卻在很大程度上損失了系統性能,由於這種數據拷貝操做不單須要佔用 CPU 時間片,同時也須要佔用額外的內存帶寬。服務器
通常來講,客戶端經過網絡接口卡向服務器端發送請求,操做系統將這些客戶端的請求傳遞給服務器端應用程序,服務器端應用程序會處理這些請求,請求處理完成之後,操做系統還須要將處理獲得的結果經過網絡適配器傳遞回去。網絡
下邊這一小節會跟讀者簡單介紹一下傳統的服務器是如何進行數據傳輸的,以及這種數據傳輸的處理過程存在哪些問題有可能會形成服務器的性能損失ide
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 系統調用的數據傳輸
優化
簡單一點來講,零拷貝就是一種避免 CPU 將數據從一塊存儲拷貝到另一塊存儲的技術。針對操做系統中的設備驅動程序、文件系統以及網絡協議堆棧而出現的各類零拷貝技術極大地提高了特定應用程序的性能,而且使得這些應用程序能夠更加有效地利用系統資源。這種性能的提高就是經過在數據拷貝進行的同時,容許 CPU 執行其餘的任務來實現的。零拷貝技術能夠減小數據拷貝和共享總線操做的次數,消除傳輸數據在存儲器之間沒必要要的中間拷貝次數,從而有效地提升數據傳輸效率。並且,零拷貝技術減小了用戶應用程序地址空間和操做系統內核地址空間之間由於上下文切換而帶來的開銷。進行大量的數據拷貝操做實際上是一件簡單的任務,從操做系統的角度來講,若是 CPU 一直被佔用着去執行這項簡單的任務,那麼這將會是很浪費資源的;若是有其餘比較簡單的系統部件能夠代勞這件事情,從而使得 CPU 解脫出來能夠作別的事情,那麼系統資源的利用則會更加有效。綜上所述,零拷貝技術的目標能夠歸納以下:操作系統
前文提到過,對於高速網絡來講,零拷貝技術是很是重要的。這是由於高速網絡的網絡連接能力與 CPU 的處理能力接近,甚至會超過 CPU 的處理能力。若是是這樣的話,那麼 CPU 就有可能須要花費幾乎全部的時間去拷貝要傳輸的數據,而沒有能力再去作別的事情,這就產生了性能瓶頸,限制了通信速率,從而下降了網絡連接的能力。通常來講,一個 CPU 時鐘週期能夠處理一位的數據。舉例來講,一個 1 GHz 的處理器能夠對 1Gbit/s 的網絡連接進行傳統的數據拷貝操做,可是若是是 10 Gbit/s 的網絡,那麼對於相同的處理器來講,零拷貝技術就變得很是重要了。對於超過 1 Gbit/s 的網絡連接來講,零拷貝技術在超級計算機集羣以及大型的商業數據中心中都有所應用。然而,隨着信息技術的發展,1 Gbit/s,10 Gbit/s 以及 100 Gbit/s 的網絡會愈來愈普及,那麼零拷貝技術也會變得愈來愈普及,這是由於網絡連接的處理能力比 CPU 的處理能力的增加要快得多。傳統的數據拷貝受限於傳統的操做系統或者通訊協議,這就限制了數據傳輸性能。零拷貝技術經過減小數據拷貝次數,簡化協議處理的層次,在應用程序和網絡之間提供更快的數據傳輸方法,從而能夠有效地下降通訊延遲,提升網絡吞吐率。零拷貝技術是實現主機或者路由器等設備高速網絡接口的主要技術之一。cdn
現代的 CPU 和存儲體系結構提供了不少相關的功能來減小或避免 I/O 操做過程當中產生的沒必要要的 CPU 數據拷貝操做,可是,CPU 和存儲體系結構的這種優點常常被太高估計。存儲體系結構的複雜性以及網絡協議中必需的數據傳輸可能會產生問題,有時甚至會致使零拷貝這種技術的優勢徹底喪失。在下一章中,咱們會介紹幾種 Linux 操做系統中出現的零拷貝技術,簡單描述一下它們的實現方法,並對它們的弱點進行分析。
零拷貝技術的發展不少樣化,現有的零拷貝技術種類也很是多,而當前並無一個適合於全部場景的零拷貝技術的出現。對於 Linux 來講,現存的零拷貝技術也比較多,這些零拷貝技術大部分存在於不一樣的 Linux 內核版本,有些舊的技術在不一樣的 Linux 內核版本間獲得了很大的發展或者已經漸漸被新的技術所代替。本文針對這些零拷貝技術所適用的不一樣場景對它們進行了劃分。歸納起來,Linux 中的零拷貝技術主要有下面這幾種:
前兩類方法的目的主要是爲了不應用程序地址空間和操做系統內核地址空間這二者之間的緩衝區拷貝操做。這兩類零拷貝技術一般適用在某些特殊的狀況下,好比要傳送的數據不須要通過操做系統內核的處理或者不須要通過應用程序的處理。第三類方法則繼承了傳統的應用程序地址空間和操做系統內核地址空間之間數據傳輸的概念,進而針對數據傳輸自己進行優化。咱們知道,硬件和軟件之間的數據傳輸能夠經過使用 DMA 來進行,DMA 進行數據傳輸的過程當中幾乎不須要 CPU 參與,這樣就能夠把 CPU 解放出來去作更多其餘的事情,可是當數據須要在用戶地址空間的緩衝區和 Linux 操做系統內核的頁緩存之間進行傳輸的時候,並無相似 DMA 這種工具可使用,CPU 須要全程參與到這種數據拷貝操做中,因此這第三類方法的目的是能夠有效地改善數據在用戶地址空間和操做系統內核地址空間之間傳遞的效率。