Kubernetes要求集羣中的每一個pod都具備惟一的,可路由的IP,Kubernetes自己不會分配IP,而是將任務留給第三方解決方案。node
本次課題的目標是找到具備最低延遲,最高吞吐量和最低安裝成本的解決方案。 因爲個人負載對延遲敏感,所以個人目的是在相對較高的網絡利用率下測量較高的百分比延遲,特別是最大負載的30%到50%之間的性能,由於我認爲這是最能表明非過載系統的最多見用例。git
這是咱們的一個參考設置,全部其餘競爭對手都會與此設置進行比較。--net=host選項表示容器繼承其主機的IP,即不涉及容器網絡。github
根據先驗原則,沒有任何容器網絡方案比其餘的會有更好的表現,這就是爲何使用此設置做爲參考的緣由。docker
Flannel是一個虛擬網絡解決方案,由CoreOS維護,它是通過充分驗證可當即投入生產的解決方案,所以安裝成本最低。將帶有Flannel的worker節點添加到k8s羣集時,Flannel會作三件事:後端
aws-vpc
在Amazon AWS實例表中註冊機器子網,此表的記錄數限制爲50,即若是將Flannel布與aws-vpc一塊兒使 用,則集羣的節點數量不能超過50,此外,此後端僅適用於Amazon的AWS。
host-gw
經過遠程主機IP建立到子網的IP路由。 須要運行Flannel的主機之間2層直連。
vxlan
建立一個虛擬VXLAN接口
因爲Flannel使用網橋接口轉發數據包,所以流量從一個容器到另外一個容器的過程當中,每一個數據包都會通過兩個網絡棧。服務器
IPvlan是Linux內核中的驅動程序,可以建立具備惟一IP的虛擬接口,而沒必要使用網橋接口。網絡
要將IP分配給具備IPvlan的容器,你必須:tcp
IPvlan是一個相對較新的解決方案,所以沒有現成的工具能夠自動執行此過程。 這使得很難在許多服務器和容器中部署IPvlan,即部署成本很高。
可是,IPvlan不須要橋接接口,而是直接將數據包從NIC轉發到虛擬接口,所以指望它的性能優於Flannel。工具
對於每一個競爭對手,執行如下步驟:性能
咱們以每秒50,000至450,000個請求(RPS)的請求速率運行基準。
在每次請求時,Nginx都會響應一個固定大小的靜態文件:350 B(內容爲100 B,標題爲250 B)或4 KB。
咱們當前的選擇是使用host-gw模式的Flannel,它沒有太多的依賴關係(例如,不須要AWS或新的Linux版本),與IPvlan相比,它易於部署,而且具備足夠的性能特性,IPvlan是備選方案,若是某個時候Flannel添加了IPvlan支持,咱們將會切換到它。
儘管aws-vpc的性能比host-gw稍好,但其50臺計算機節點的侷限性以及將其硬連線到Amazon的AWS的事實對咱們來講都是一個障礙。
在每秒50,000個的請求速度下,全部候選者都表現出使人滿意的性能,主要趨勢是:IPVlan表現最佳,host-gw和aws-vpc緊隨其後,vxlan表現最差。
IPvlan略優於host-gw和aws-vpc,可是在99.99 %ile這個指標上是最差的,host-gw的性能略優於aws-vpc。
這種負載在生產中也很常見,所以這些結果尤其重要。
IPvlan再次顯示出最佳性能,可是在99.99和99.999 %ile這兩個指標上aws-vpc更勝一籌,host-gw在95和99% %ile上優於aws-vpc。
在大多數狀況下,延遲接近250,000 RPS(350 B狀況),但在99.5 %ile以後迅速增加,這意味着咱們已經接近最大RPS。
這是理論上能產生合理結果的最大RPS,IPvlan再次領先,延遲比--net-host差30%左右:
有趣的是,host-gw的性能比aws-vpc更好:
在500,000 RPS下,只有IPvlan仍然有效,表現甚至優於--net=host,可是延遲是如此之高,以致於咱們認爲這對延遲敏感的程序毫無用處。
較大的響應會形成較高的網絡使用率,但測試結果看起來與較小的響應幾乎相同:
Host-gw具備使人驚訝的99.999%ile,對於較低的百分位數也顯示出良好的結果。
這是在大的請求響應下的最大RPS,與小的請求響應測試用例不一樣,aws-vpc的性能比host-gw好得多,Vxlan再次從圖中排除。
爲了理解本文並重現咱們的測試環境,你應該熟悉有關高性能的基礎知識。
這些文章提供了有關該主題的有用看法:
擴展Linux網絡堆棧 from the Linux kernel documentation
爲了支持加強聯網功能和IPvlan,已經安裝了帶有Intel ixgbevf驅動程序的Linux內核4.3.0版本。
現代NIC經過多箇中斷請求(IRQ)線提供接收方擴展(RSS),EC2在虛擬化環境中僅提供兩條中斷線,所以咱們測試了幾種RSS和接收數據包導向(RPS)接收數據包導向(RPS)配置,最終獲得如下配置,部分由Linux內核文檔提供:
兩個NUMA節點中的每一個節點上的第一個核都配置爲接收來自NIC的中斷。
使用lscpu將CPU與NUMA節點匹配:
$ lscpu | grep NUMA NUMA node(s): 2 NUMA node0 CPU(s): 0-8,18-26 NUMA node1 CPU(s): 9-17,27-35
這是經過將0和9寫入/proc/irq/<num>/smp_affinity_list來實現的,其中IRQ編號是經過grep eth0 /proc/interrupts得到的:
$ echo 0 > /proc/irq/265/smp_affinity_list $ echo 9 > /proc/irq/266/smp_affinity_list
已測試了RPS的幾種組合,爲了提升延遲,咱們僅使用CPU 1–8和10–17減輕了IRQ處理處理器的負擔。與IRQ的smp_affinity不一樣,rps_cpus sysfs文件條目沒有_list對應項,所以咱們使用位掩碼列出RPS能夠將流量轉發到的CPU:
$ echo "00000000,0003fdfe" > /sys/class/net/eth0/queues/rx-0/rps_cpus $ echo "00000000,0003fdfe" > /sys/class/net/eth0/queues/rx-1/rps_cpus
將全部NUMA 0處理器(包括HyperThreading,即CPU 0-八、18-26)設置爲tx-0,將NUMA 1(CPU 9-1七、27-37)設置爲tx-12:
$ echo "00000000,07fc01ff" > /sys/class/net/eth0/queues/tx-0/xps_cpus $ echo "0000000f,f803fe00" > /sys/class/net/eth0/queues/tx-1/xps_cpus
咱們計劃使用60k常駐鏈接,官方文檔建議將其四捨五入爲最接近的2的冪:
$ echo 65536 > /proc/sys/net/core/rps_sock_flow_entries $ echo 32768 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt $ echo 32768 > /sys/class/net/eth0/queues/rx-1/rps_flow_cnt
Nginx使用18個worker,每一個worker都有本身的CPU(0-17),經過worker_cpu_affinity選項設置:
**workers** 18; **worker_cpu_affinity** 1 10 100 1000 10000 ...;
Tcpkali沒有內置的CPU親和性支持,爲了利用RFS,咱們在任務集中運行tcpkali並調整調度程序,防止線程遷移的發生:
$ echo 10000000 > /proc/sys/kernel/sched_migration_cost_ns $ taskset -ac 0-17 tcpkali --threads 18 ...
與咱們嘗試過的其餘設置相比,此設置可以更均勻地在CPU內核之間分配中斷負載,並以相同的延遲實現更好的吞吐量。
CPU 0和9專門處理NIC中斷,不處理數據包,但它們還是最繁忙的:
RedHat的調整也與網絡延遲配置文件一塊兒使用,爲了最大程度地減小nf_conntrack的影響,添加了NOTRACK規則,內核參數已調整爲支持大量tcp鏈接:
fs.file-max = 1024000 net.ipv4.ip_local_port_range = "2000 65535" net.ipv4.tcp_max_tw_buckets = 2000000 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 10 net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_low_latency = 1