不幸的是,對于一些更加專業(yè)的工作,Vanilla Linux(譯注:Linux 的內(nèi)核版本,代號“香草”) 內(nèi)核的網(wǎng)絡(luò)速度是不夠的。舉個例子,在 CloudFlare,我們持續(xù)地處理洪水般的數(shù)據(jù)包。 Vanilla Linux 處理速度僅能達(dá)到約 1M pps (譯注:單位 packet per seconds),這在我們的工作環(huán)境下是不夠的,特別是網(wǎng)卡有能力處理大量的數(shù)據(jù)包?,F(xiàn)代 10Gbps 網(wǎng)卡的處理能力通常至少達(dá)到 10M pps 。
內(nèi)核不給力
我們做一個小實(shí)驗(yàn)來說明修改?Linux 確實(shí)是有必要的。我們看看理想狀態(tài)下內(nèi)核能處理多少數(shù)據(jù)包。把數(shù)據(jù)包傳遞到用戶空間的代價是高昂的,讓我們嘗試一下在網(wǎng)絡(luò)驅(qū)動程序收到數(shù)據(jù)包后就立刻丟棄它們。據(jù)我所知,Linux 上不修改內(nèi)核丟棄數(shù)據(jù)包最快的方法是在?PREROUTING iptables 上設(shè)置一些丟棄規(guī)則。
Shell
1
2
3
4
5
6
7
$ sudo iptables -t raw -I PREROUTING -p udp --dport 4321 --dst 192.168.254.1 -j DROP
$ sudo ethtool -X eth2 weight 1
$ watch 'ethtool -S eth2|grep rx'
rx_packets:?????? 12.2m/s
rx-0.rx_packets:?? 1.4m/s
rx-1.rx_packets:?? 0/s
...
如上所示,?Ethtool(譯者注:Ethtool 是 Linux 下用于查詢及設(shè)置網(wǎng)卡參數(shù)的命令)的統(tǒng)計顯示,網(wǎng)卡能達(dá)到每秒接收 12M 數(shù)據(jù)包的速度。通過 ethtool -X 來操作網(wǎng)卡上的間接表,可以將所有的數(shù)據(jù)包引向 0 號 RX 隊列。正如我們看到的,在一顆 CPU 上,內(nèi)核處理隊列的速度可以達(dá)到 1.4M pps。
在單核上能達(dá)到 1.4M pps 是一個相當(dāng)不錯的結(jié)果,但不幸的是協(xié)議棧卻不能擴(kuò)展。當(dāng)數(shù)據(jù)包被分配到多核上,這個成績會急劇下降。讓我們看看把數(shù)據(jù)包分到 4 個 RX 隊列的結(jié)果。
Shell
1
2
3
4
5
6
7
$ sudo ethtool -X eth2 weight 1 1 1 1
$ watch 'ethtool -S eth2|grep rx'
rx_packets:???? 12.1m/s
rx-0.rx_packets: 477.8k/s
rx-1.rx_packets: 447.5k/s
rx-2.rx_packets: 482.6k/s
rx-3.rx_packets: 455.9k/s
此時每個核的處理速度是 480k pps。這是個糟糕的消息。即使樂觀地假設(shè)增加多個核心不會進(jìn)一步地造成性能的下降,處理數(shù)據(jù)包的核心也要多達(dá) 20 個才能達(dá)到線速度。所以內(nèi)核是不起作用的。
內(nèi)核旁路前來救駕
CC BY 2.0?image?by Matt Brown
關(guān)于 Linux 內(nèi)核網(wǎng)絡(luò)性能的局限早已不是什么新鮮事了。在過去的幾年中,人們多次嘗試解決這個問題。最常用的技術(shù)包括創(chuàng)建特別的 API,來幫助高速環(huán)境下的硬件去接收數(shù)據(jù)包。不幸的是,這些技術(shù)總是在變動,至今沒有出現(xiàn)一個被廣泛采用的技術(shù)。
這里列出一些廣為人知的內(nèi)核旁路技術(shù)。
PACKET_MMAP
Packet mmap 是 Linux 上的API,用來實(shí)現(xiàn)數(shù)據(jù)包快速嗅探。然而它不是嚴(yán)格意義上的內(nèi)核旁路技術(shù),它是技術(shù)列表中的一個特例 —— 可以在 Vanilla 內(nèi)核上使用。
PF_RING
PF_RING?是另一個已知的技術(shù),用來提升捕獲數(shù)據(jù)包的速度。不像 packet_mmap,PF_RING 不在內(nèi)核主線中,需要一些特殊模塊。通過 ZC 驅(qū)動和把模式設(shè)置成 transparent_mode = 2(譯者注:是 PF_RING 的一種模式),只把數(shù)據(jù)包傳遞給 PF_RING 客戶端,而不會經(jīng)過內(nèi)核網(wǎng)絡(luò)協(xié)議棧。由于內(nèi)核比較緩慢,這樣可以確保高速運(yùn)轉(zhuǎn)。
Snabbswitch
Snabbswitch?是一個 Lua 網(wǎng)絡(luò)框架,主要用來寫 L2 應(yīng)用。它可以完全接管一個網(wǎng)卡,并且在用戶空間實(shí)現(xiàn)硬件驅(qū)動。它在一個 PCI 設(shè)備上實(shí)現(xiàn)了用戶空間 IO(UIO),把設(shè)備寄存器映射到 sysfs 上(譯者注:sysfs?是 Linux 內(nèi)核中設(shè)計較新的一種虛擬的基于內(nèi)存的文件系統(tǒng)) 。這樣就可以非??斓夭僮?,但是這意味著數(shù)據(jù)包完全跳過了內(nèi)核網(wǎng)絡(luò)協(xié)議棧。
DPDK
DPDK?是一個用 C 語言實(shí)現(xiàn)的網(wǎng)絡(luò)框架,專門為 Intel 芯片創(chuàng)建。它本質(zhì)上和 snabbswitch 類似,因?yàn)樗彩且粋€基于UIO 的完整框架。
Netmap
Netmap?也是一個豐富的網(wǎng)絡(luò)框架,但是和 UIO 技術(shù)不同,它是由幾個內(nèi)核模塊來實(shí)現(xiàn)的。為了和網(wǎng)絡(luò)硬件集成在一起,用戶需要給內(nèi)核網(wǎng)絡(luò)驅(qū)動打補(bǔ)丁。增加復(fù)雜性的最大好處是有一個詳細(xì)文檔說明的、設(shè)備廠商無關(guān)的和清晰的 ?API。
由于內(nèi)核旁路技術(shù)的目的是不再讓內(nèi)核處理數(shù)據(jù)包,所以我們排除了 packet_mmap。因?yàn)樗荒芙邮諗?shù)據(jù)包?—— 它只是一個嗅探數(shù)據(jù)包的快速接口。同樣,沒有 ZC 模塊的 PF_RING?也沒有什么吸引力,因?yàn)樗闹饕繕?biāo)是加速 libpcap(譯者注:libpcap是unix/linux平臺下的網(wǎng)絡(luò)數(shù)據(jù)包捕獲函數(shù)包,大多數(shù)網(wǎng)絡(luò)監(jiān)控軟件都以它為基礎(chǔ))。
我們已經(jīng)排除了兩種技術(shù),但很不幸的是,在余下的解決方案中,也沒有我們能夠使用的!
讓我告訴你原因。為了用?剩下的技術(shù)?實(shí)現(xiàn)內(nèi)核旁路技術(shù):Snabbswitch、DPDK 和 netmap 會接管整個網(wǎng)卡,不允許網(wǎng)卡的任何流量經(jīng)過內(nèi)核。我們在 CloudFlare,根本不可能讓一個分擔(dān)負(fù)載的應(yīng)用程序獨(dú)占整個網(wǎng)卡。
話說回來,很多人使用上面的技術(shù)。在其他環(huán)境中占用一個網(wǎng)卡,來實(shí)現(xiàn)旁路也許是可以接受的。
Solarflare 上的 EF_VI
雖然上面列出的技術(shù)需要占用整個網(wǎng)卡,但還有其它的選擇。
Solarflare 網(wǎng)卡支持?OpenOnload,一個神奇的網(wǎng)卡加速器。它通過如下方式來實(shí)現(xiàn)內(nèi)核旁路,在用戶空間實(shí)現(xiàn)網(wǎng)絡(luò)協(xié)議棧,并使用 LD_PRELOAD 覆蓋目標(biāo)程序的網(wǎng)絡(luò)系統(tǒng)調(diào)用。在底層訪問網(wǎng)卡時依靠 “EF_VI” 庫。這個庫可以直接使用并且有很好的說明文檔。
EF_VI?作為一個專用庫,僅能用在 Solarflare 網(wǎng)卡上,你可能想知道它實(shí)際是如何工作的。 EF_VI 是以一種非常聰明的方式重新使用網(wǎng)卡的通用功能。
在底層,每個 EF_VI 程序可以訪問一條特定的 RX 隊列,這條 RX 隊列對內(nèi)核不可見的。默認(rèn)情況下,這個隊列不接收數(shù)據(jù),直到你創(chuàng)建了一個 EF_VI “過濾器”。這個過濾器只是一個隱藏的流控制規(guī)則。你用?ethtool -n 也看不到,但實(shí)際上這個規(guī)則已經(jīng)存在網(wǎng)卡中了。對于 EF_VI 來說,除了分配 RX 隊列并且管理流控制規(guī)則,剩下的任務(wù)就是提供一個API 讓用戶空間可以訪問這個隊列。
分叉驅(qū)動
雖然?EF_VI 是 Solarflare 所特有的,其他網(wǎng)卡還是可以復(fù)制這個技術(shù)。首先我們需要一個支持多隊列的網(wǎng)卡,同時它還支持流控制和操作間接表。
有了這些功能,我們可以:
正常啟動網(wǎng)卡,讓內(nèi)核來管理一切。
修改間接表以確保沒有數(shù)據(jù)包流向任一 RX 隊列。比如說我們選擇 16 號 RX 隊列。
通過流控制規(guī)則將一個特定的網(wǎng)絡(luò)流引到 16號 RX 隊列。
完成這些,剩下的步驟就是提供一個用戶空間的 API ,從 16 號 RX 隊列上接收數(shù)據(jù)包,并且不會影響其他任何隊列。
這個想法在 DPDK 社區(qū)被稱為“分叉驅(qū)動”。它們打算在??2014 年創(chuàng)建分叉驅(qū)動,不幸的是?這個補(bǔ)丁?還沒進(jìn)入內(nèi)核的主線。
虛擬化方法
針對 intel 82599 還有另外一種選擇。我們可以利用網(wǎng)卡上的虛擬化功能來實(shí)現(xiàn)內(nèi)核旁路,而不需要通過分叉驅(qū)動程序。
首先我簡單說下背景。有結(jié)果證明,在虛擬化世界中將數(shù)據(jù)包從主機(jī)傳遞到客戶機(jī),虛擬機(jī)通常是瓶頸。因此,這些年對虛擬化性能的需求與日俱增,通過軟件模擬網(wǎng)絡(luò)硬件的仿真技術(shù)成為了影響性能的主要障礙。
網(wǎng)卡廠商增加一些特性來加速虛擬客戶端。其中一項虛擬化技術(shù),要求網(wǎng)卡虛擬成多個 PCI 設(shè)備。虛擬客戶端可以操作這些虛擬接口,無需與主機(jī)操作系統(tǒng)進(jìn)行任何合作。我演示一下它是如何工作的。舉個例子,這是我本機(jī)上的 82599 網(wǎng)卡。這個“真實(shí)的”設(shè)備被稱為 PF(物理功能)接口:
Shell
1
2
$ lspci
04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)
我們要求這個設(shè)備創(chuàng)建一個 VF(虛擬功能)設(shè)備:
Shell
1
2
3
4
$ echo 1 > /sys/class/net/eth3/device/sriov_numvfs
$ lspci
04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)??
04:10.1 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function (rev 01)
比如說一個 KVM 客戶端很容易使用這個假的 PCI 設(shè)備。同時,我們還是能夠使用主機(jī)環(huán)境。要做到這些僅需要加載 “ixgbevf” 內(nèi)核模塊,之后會出現(xiàn)另一個 “ethX” 接口。
你或許想知道內(nèi)核旁路技術(shù)干了什么。內(nèi)核沒有利用“ixgbevf”設(shè)備正常聯(lián)網(wǎng),我們可以把它專門用在內(nèi)核旁路上。這樣看起來可以在 “ixgbevf” 設(shè)備運(yùn)行 DPDK。
概括來說:這個想法可以讓 PF 設(shè)備正常處理內(nèi)核工作,而 VF 接口專門用在內(nèi)核旁路技術(shù)上。由于 VF 是專用的,所以我們可以運(yùn)行“接管整個網(wǎng)卡”的技術(shù)。
這聽起來似乎不錯,實(shí)際上卻沒那么簡單。首先,只有 DPDK 支持“ixgbevf”設(shè)備,netmap,snabbswtich 和 PF_RING 是不支持的。默認(rèn)情況下, VF 接口不能接收任何數(shù)據(jù)包。若通過 PF 發(fā)送數(shù)據(jù)給 VF ,你需要給?ixgbe 打上這個補(bǔ)丁。有了它,你可以對 VF 進(jìn)行尋址,即在ethtool中對“活動”“隊列號的高位進(jìn)行編碼。
Shell
1
$ ethtool -N eth3 flow-type tcp4 dst-ip 192.168.254.30 dst-port 80 action 4294967296
最后一個障礙出現(xiàn)了,在 82599 芯片上啟用 VF 功能,RSS 組的最大規(guī)模變小了(譯者注:Really Simple Syndication,簡易信息聚合)。沒有虛擬化時,82599 可以在 16 個 CPU 核上進(jìn)行 RSS 。但隨著 VF 的啟用,這個數(shù)量卻變成了 4。如果 PF 上的流量比較低,只使用 4 個核來發(fā)布可能還好。不幸的是,我們在 Cloudflare 需要處理大規(guī)模的 RSS 組。
結(jié)束語
完成內(nèi)核旁路技術(shù)沒有那么簡單。雖然存在很多開源的技術(shù),但它們看起來都需要一塊專用的的網(wǎng)卡。這里我們展示了 3 個可以選擇的框架:
類似 EF_VI, 隱藏 RX 隊列
DPDK 分叉驅(qū)動
VF 技術(shù)
不幸的是,在我們的環(huán)境下,這么多技術(shù)中能起作用的似乎只有 EF_VI。我們祈禱開源的內(nèi)核旁路 API 趕緊出現(xiàn),唯一的要求是不需要一塊專用的網(wǎng)卡。
?
評論
查看更多