RPS/RFS 功能是在Linux- 2.6.35中有google的工程師提交的兩個補丁,這兩個補丁的出現主要是基於如下兩點現實的考慮:html
(1) 這兩個補丁的出現,是因爲服務器的CPU愈來愈強勁,能夠到達十幾核、幾十核,而網卡硬件隊列則才4個、8個,這種發展的不匹配形成了CPU負載的不均衡。服務器
(2) 上面的提到的是多隊列網卡的狀況,在單隊列網卡的狀況下,RPS/RFS至關於在系統層用軟件模擬了多隊列的狀況,以便達到CPU的均衡。網絡
出現RFS/RPS的緣由主要是因爲過多的網卡收包和發包中斷集中在一個CPU上,在系統繁忙時,CPU對網卡的中斷沒法響應,這樣致使了服務器端的網絡性能下降,從這裏能夠看出其實網絡性能的瓶頸不在於網卡,而是CPU,由於如今的網卡不少都是萬兆而且多隊列的,若是有過多的中斷集中在一個CPU上,將致使該CPU沒法處理,因此可使用該方法將網卡的中斷分散到各個CPU上。但對於CentOS 6.1已經支持了。數據結構
當網卡驅動加載時,經過獲取的網卡型號,獲得網卡的硬件queue的數量,並結合CPU核的數量,最終經過Sum=Min(網卡queue,CPU core)得出所要激活的網卡queue數量(Sum),並申請Sum箇中斷號,分配給激活的各個queue,當某個queue收到報文時,觸發相應的中斷,收到中斷的核,將該任務加入到協議棧負責收包的該核的NET_RX_SOFTIRQ隊列中(NET_RX_SOFTIRQ在每一個核上都有一個實例),在NET_RX_SOFTIRQ中,調用NAPI的收包接口,將報文收到有多個netdev_queue的net_device數據結構中。架構
當CPU能夠平行收包時,就會出現不一樣的核收取了同一個queue的報文,這就會產生報文亂序的問題,解決方法是將一個queue的中斷綁定到惟一的一個核上去,從而避免了亂序問題。app
查看網卡是否支持MSI-X能夠直接查看 interrupts 文件,看關鍵字 MSI 就知道了:負載均衡
# grep -i msi /proc/interruptsdom
在Broadcom的網卡手冊上有關於MSI和MSI-X的定義:ide
MSI Version. This is the Message Signaled Interrupts (MSI) version being used. The option MSI corresponds to the PCI 2.2 specification that supports 32 messages and a single MSI address value. The option MSI-X corresponds to the PCI 3.0 specification that supports 2,048 messages and an independent message address for each message.性能
實際應用場景中,MSI方式的中斷對多核cpu的利用狀況不佳,網卡中斷所有落在某一個cpu上,即便設置cpu affinity也沒有做用,而MSI-X中斷方式能夠自動在多個cpu上分擔中斷。
RPS(Receive Packet Steering)主要是把軟中斷的負載均衡到各個cpu,簡單來講,是網卡驅動對每一個流生成一個hash標識,這個HASH值得計算能夠經過四元組來計算(SIP,SPORT,DIP,DPORT),而後由中斷處理的地方根據這個hash標識分配到相應的CPU上去,這樣就能夠比較充分的發揮多核的能力了。通俗點來講就是在軟件層面模擬實現硬件的多隊列網卡功能,若是網卡自己支持多隊列功能的話RPS就不會有任何的做用。該功能主要針對單隊列網卡多CPU環境,如網卡支持多隊列則可以使用SMP irq affinity直接綁定硬中斷。
圖1 只有RPS的狀況下(來源網絡)
因爲RPS只是單純把數據包均衡到不一樣的cpu,這個時候若是應用程序所在的cpu和軟中斷處理的cpu不是同一個,此時對於cpu cache的影響會很大,那麼RFS(Receive flow steering)確保應用程序處理的cpu跟軟中斷處理的cpu是同一個,這樣就充分利用cpu的cache,這兩個補丁每每都是一塊兒設置,來達到最好的優化效果, 主要是針對單隊列網卡多CPU環境。
圖2:同時開啓RPS/RFS後(來源網絡)
rps_flow_cnt,rps_sock_flow_entries,參數的值會被進位到最近的2的冪次方值,對於單隊列設備,單隊列的rps_flow_cnt值被配置成與 rps_sock_flow_entries相同。
RFS依靠RPS的機制插入數據包到指定CPU的backlog隊列,並喚醒那個CPU來執行
RSS(receive side scaling)是有微軟提處理,經過這項技術可以將網絡流量分載到多個cpu上,下降單個cpu的佔用率。默認狀況下,每一個cpu覈對應一個rss隊列。ixgbe驅動將收到的數據包的源、目的ip地址和端口號,交由網卡硬件計算出一個rss hash值,再根據這個hash值來決定將數據包分配到哪一個隊列中。經過cat /proc/interrupts |grep 網卡名的方式,就能夠看到網卡使用了幾個rss通道。
RSS(Receive-side scaling,接收端調節)技術,RSS是和硬件相關聯的,必需要有網卡的硬件進行支持,RSS把發數據包分配到不一樣的隊列中,其中HASH值的計算式在硬件中完成的,而後經過affinity的調整把不一樣的中斷映射的不一樣的Core上。下面是Linux內核對RFS和RSS描述。
For a multi-queue system, if RSS is configured so that a hardware
receive queue is mapped to each CPU, then RPS is probably redundant
and unnecessary. If there are fewer hardware queues than CPUs, then
RPS might be beneficial if the rps_cpus for each queue are the ones that
share the same memory domain as the interrupting CPU for that queue.
在Intel架構上的一些硬件上是有該功能的。
On the Intel architecture, multi-queue NICs use MSI-X (the extended version of Message Signaled Interrupts) to send interrupts to multiple cores. The feature that distributes arriving packets to different CPUs based on (hashed) connection identifiers is called RSS (Receive Side Scaling) on Intel adapters, and its kernel-side support on Windows was introduced as part of the Scalable Networking Pack in Windows 2003 SP2.
This performance enhancement works as follows: Incoming packets are distributed over multiple logical CPUs (e.g. cores) based on a hash over the source and destination IP addresses and port numbers. This hashing ensures that packets from the same logical connection (e.g. TCP connection) are always handled by the same CPU/core. On some network adapters, the work of computing the hash can be outsourced to the network adapter. For example, some Intel and Myricom adapters compute a Toeplitz hashfrom these header fields. This has the beneficial effect of avoiding cache misses on the CPU that performs the steering - the receiving CPU will usually have to read these fields anyway.
Receive-Side Scaling (RSS), also known as multi-queue receive, distributes network receive processing across several hardware-based receive queues, allowing inbound network traffic to be processed by multiple CPUs. RSS can be used to relieve bottlenecks in receive interrupt processing caused by overloading a single CPU, and to reduce network latency。(https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/network-rss.html)
經過上面的介紹能夠知道,對於RSS和RFS的區別,它們都是把同一個流的數據包給同一個CPU,可是RSS是使用硬件實現的,而RFS是純軟件實現的。
SMP IRQ affinity Linux 2.4內核以後引入了將特定中斷綁定到指定的CPU的技術,稱爲SMP IRQ affinity。
smp_affinity是否須要設置,根據網卡是否支持多隊列,若是網卡支持多隊列則設置纔有做用,若是網卡有多隊列,就會有多箇中斷號,這樣就能夠把不一樣的中斷號分配到不一樣CPU上,這樣中斷號就能相對均勻的分配到不一樣的CPU上。
這裏簡單的理解一下,smp_affinity值得映射關係,下面簡單的舉個例子:
若是cat /proc/irq/84/smp_affinity的值爲:20(二進制爲:00100000),則84這個IRQ的親和性爲#5號CPU。
每一個IRQ的默認的smp affinity在這裏:cat /proc/irq/default_smp_affinity,默認值是全F。
可是對於單隊列的網卡配置「smp_affinity」和「smp_affinity_list」對多CPU無效。
若是是單隊列的話/proc/sys/net/core/rps_sock_flow_entries值和rps_flow_cnt設置爲相同,rps更多的是針對網卡驅動是NAPI方式的,若是應用場景更可能是內核的forward,RPS就足夠了,再在該基礎上使用RFS也不會有性能的提高。
在執行腳本向/sys/class/net/eth0/queues/rx-0/ rps_cpus文件中寫對應的數據時,提示
./set_irq_affinity.sh
./set_irq_affinity.sh: line 52: echo: write error: Value too large for defined data type
這是因爲rps_cpus文件中的數,須要和CPU的個數相匹配,當寫入的數據大於CPU的個數時,會出現上面的錯誤提示信息。
可以使用逗號爲不連續的 32 位組限定 smp_affinity 值。在有 32 個以上核的系統有這個要求。例如:如下示例顯示在一個 64 核系統的全部核中提供 IRQ 40。
# cat /proc/irq/40/smp_affinity
ffffffff,ffffffff
在 64 核系統的上 32 核中提供 IRQ 40,請執行:
# echo 0xffffffff,00000000 > /proc/irq/40/smp_affinity
# cat /proc/irq/40/smp_affinity
ffffffff,00000000
RFS須要內核編譯CONFIG_RPS選項,RFS才起做用。全局數據流表(rps_sock_flow_table)的總數能夠經過下面的參數來設置:
/proc/sys/net/core/rps_sock_flow_entries
每一個隊列的數據流表總數能夠經過下面的參數來設置:
/sys/class/net//queues/rx/rps_flow_cnt
echo ff > /sys/class/net//queues/rx-/rps_cpus
echo 4096 > /sys/class/net//queues/rx-/rps_flow_cnt
echo 30976 > /proc/sys/net/core/rps_sock_flow_entries
對於2個物理cpu,8核的機器爲ff,具體計算方法是第一顆cpu是00000001,第二個cpu是00000010,第3個cpu是 00000100,依次類推,因爲是全部的cpu都負擔,因此全部的cpu數值相加,獲得的數值爲11111111,十六進制就恰好是ff。而對於 /proc/sys/net/core/rps_sock_flow_entries的數值是根據你的網卡多少個通道,計算得出的數據,例如你是8通道的 網卡,那麼1個網卡,每一個通道設置4096的數值,8*4096就是/proc/sys/net/core/rps_sock_flow_entries 的數值,對於內存大的機器能夠適當調大rps_flow_cnt,
參考文獻: