【前言】最近在實習公司用到了solarflare的萬兆網卡,用到了網卡的openonload技術還有TCPDirect模式代碼的編寫,其理論基礎都是內核旁路。網上關於內核旁路技術的介紹基本就兩篇,我結合solarflare的技術文檔,總結一下。
原文地址(需要翻牆):https://blog.cloudflare.com/why-we-use-the-linux-kernels-tcp-stack/
轉:最近的一篇文章提出了“我們為什么使用Linux內核的TCP協議棧”的問題,並在Hacker News引發了非常有意思的討論。我的經驗絕大部分來自於在這里和生產環境中成千的機器打交道,我可以試着從這個角度回答這個問題。
讓我們從一個更寬泛的問題開始 – 到底什么才是運行一個操作系統的意義?如果你打算運行一個單獨的應用,那使用一個包含幾千萬行代碼的內核聽起來就像一個負擔。但實際上,我們絕大多數的人都決定要使用某種類型的操作系統,並且我們這么做主要有兩個原因。首先,操作系統層帶來了硬件的獨立性和容易使用的API。有了這些我們可以專注於編寫適用於任何機器的代碼 – 而不只是我們目前所擁有的特定的硬件。其次,操作系統添加了一個時間分享的層。這讓我們能同時運行多個應用。不管是一個額外的HTTP 服務器還是一次Bash會話,這個能在多個進程之間共享資源十分重要。所有被內核暴露出來的資源都可以在多個進程之間進行共享。
一個重要的問題,tcp/ip協議無法帶來多CPU的線性加速。
一、用戶空間網絡
對於網絡棧來說並沒有什么不同。通過使用通用的操作系統網絡協議棧我們擁有了運行多個網絡應用的能力。然而如果我們為了運行一個用戶空間的網絡棧,將網絡硬件專用於一個應用程序的話,這個能力就丟失了。通過要求將網卡僅為一個進程使用,你就失去了和你的服務器同時運行的能力另外一個應用,如一個SSH會話,的能力。
可能這聽起來有點不可思議,但是這正是絕大多數的用戶空間網絡棧技術的目的。用來完整描述這個名詞叫做“完全內核旁路(full kernel bypass)”。這想法是繞過內核,然后直接從用戶空間的進程使用網絡硬件。
在Linux的生態環境中,有一些已經存在的技術。不是所有的都是開源的:
-
PF_RING
-
Snabbswitch
-
DPDK
-
Netmap
我已經在之前的一篇文章講過它們。所有的的這些技術都需要將網卡整個移交給一個單獨的進程。換句話說:完全有可能編寫你自己的網絡協議棧,讓他變得聰明,專注於高級的特性,並且針對性能進行優化。但是這會招來一個很大的開銷 – 每一張網卡最多只能將它用於一個進程。
關於虛擬網卡(VF)這里有一個小小改變,但是我們不要在這里討論它——它無法工作。我已經在“虛擬化方案”的那一段中講到了它。
但即使有種種障礙,我也不能簡單地否定內核旁路的好處。確實有很多人在運行自定義的網絡協議棧,並且他們可能出於下面兩個原因之一:
-
延遲
-
性能(更低的CPU消耗,更高的吞吐量)
延遲對於高率交易(high frequency tradin)來說至關重要。交易者能支付得起自定義的硬件,和各種復雜的私有網絡棧。運行一個閉源的TCP協議棧會讓我很不自在。
在CloudFlare的內核旁路
https://blog.cloudflare.com/kernel-bypass/
https://blog.csdn.net/wwh578867817/article/details/50139819
盡管這么說,在CloudFlare我們也的確使用內核繞行。我們是上面提到的第二種人,我們很在乎性能。更加明確的說,我們遭受着IRQ風暴的問題。Linux的網絡棧一秒鍾能處理的數據包是有限的。當達到上限的時候,所有的CPU都忙於接收數據包。在這種情形下,數據包要么被丟棄,要么會導致應用CPU匱乏( starve of CPU)。盡管在正常的情況下我們不用處理IRQ風暴,但是當我們是一次三層(OSI中的第三層)DDoS攻擊的對象的時候就會成為問題。這是一種攻擊目標被各種隨意的不屬於任何合法連接數據淹沒的攻擊 – 通常來說都是欺騙數據包(spoofed packets)。 在一些攻擊中我們一台服務器會遭受一秒高達3Mpps的數據包。一個廣泛適用的法則就是Linux的iptables能在一個不錯的服務器上處理約1Mpps的數據包的同時,仍為應用留下足夠多的CPU。這個數字還可以通過調優來提高。
對於這種規模的攻擊來說Linux內核對於我們來說是不夠的。我們必須找到解決方法。我們沒有使用之前提到的“完全內核旁路”,相反的我們使用的是我們自稱為的“部分內核旁路”。通過它內核仍然保留網卡的的擁有權,並且能讓我們只在一個單獨的“接收隊列(Rx Queue)”上執行旁路。我們在SolarFlare的網卡上使用Solarflare的EFVI API。為了支持Intel的網卡,我們給Netmap添加了一個部分內核旁路的特性:這個在這篇文章里有講到。通過這個技術我們可以將我們的抗DDoS iptable分擔到一個十分快的用戶進程。這讓Linux不用再處理攻擊的數據包,因此避免了IRQ風暴的問題。
二、一個完全的用戶空間TCP協議棧如何呢?
我們的同事經常會問我:我們什么我們不用Solarflare的OpenOnload框架來運行我們的Nginx呢,使用十分快速的用戶空間TCP?
是的,這會更快,但是沒有證據這能產生什么實際上的不同。我們服務器絕大多數使用的CPU被用在了用戶空間的Nginx進程而不是操作系統。CPU主要用在經常的Nginx的簿記和我們的Lua應用邏輯,而不是處理網絡。我估計通過旁路我們能節省大約5%-10%的CPU,這(至少在目前看來)並不值當。但是對於量化交易的延時很重要。 其次,為了Nginx使用內核旁路會干擾我們平常使用的調試工具。我們的systemtap腳本會變得沒有用。Linux的netstat統計會停止記錄重要的事件,並且tcpdump不會再工作。然后我們的DDoS緩解棧來說也有一個問題。我們是iptables的重度用戶,正如我們在這個BlackHat的演講中講到的。自定義的TCP協議棧是沒有入”hashlimits”和”ipsets”這類東西的。
但是不只防火牆的特性。Linux的TCP協議棧有一些特別有用的非常重要的支持,如RFC4821,可以通過用sysctl的sys.net.ipv4.tcp_mtu_probing來設置。這種支持當一個用戶在一個ICMP的黑洞后面來說是非常重要的。可以通過閱讀這個文章來了解PMTU。
最后,每一個TCP協議棧都會有一些自己的問題和怪異模式。我們已經描述了三種Linux TCP棧中不是很顯而易見的Linux怪異問題:
-
讀緩沖中垃圾回收器闖入的問題
-
關於太多監聽套接字的問題
-
一個套接字可寫意味着什么
想像一下要在一個閉源或者年輕的TCP協議棧中要調試這種問題意味着什么。
三、結論
有兩個問題:
第一,目前還沒有穩定的開源的部分內核旁路技術。我們希望Netmap能搶占這個商機,並且我們在積極地通過我們自己的補丁來支持它。
第二,Linux TCP協議棧有很多重要的特性和優秀的調試能力。需要花費幾年的的時間來能挑戰這個豐富的生態系統。
鑒於這些原因,基於用戶空間的網絡是不大可能成為主流的。在實踐中,我只能想象少數合理的應用需要用到內核旁路技術:
1、軟件的交換機或者路由器。這里你想將網卡交由應用來處理,讓它們來處理原始的數據包並且完全繞開內核。
2、專用的負載均衡器。類似的,如果該機器只用來做數據包的隨機處理( packet shuffling ),那繞過內核就是合理的。
3、對於選定的高吞吐/低延遲的應用進行部分旁路。這就是在我們的DDoS緩解系統中用到的。不幸的是,我尚不知道有什么穩定且開源的TCP協議棧是適合這一類的。
4、對於普通用戶來說,Linux的網絡棧才是正確的選擇。盡管這比起自己重寫TCP協議棧來說不那么振奮人心,但是我們專注於理解Linux棧的性能並且修復其中問題。已經有一些正在進行的嚴肅的提議來改善這個年老優秀的Linux TCP協議棧。
5、量化交易高頻、中低頻交易可以使用。