鳥哥的 Linux 私房菜

使用 10G switch 需要注意的效能問題

最近更新日期:2019/02/13

最近這三、四年來,網路的使用頻率越來越高,加上虛擬化與共用檔案系統的任務,因此網路的頻寬越來越重要!傳統的 10G 以上設備, 光是光纖就貴森森,因此,最近這幾年來,大量的 RJ-45 接頭的 10G 設備的支援,就顯得很重要!因為,可以向下相容 1Gbps 的設備之外, 頻寬可以增加 10 倍哩!只是,這種 10G, Gbps 的共存環境下,其實存在某些很特別的問題,大部分的時間你不會注意到, 但是,如果你使用的環境跟鳥哥一樣時,你可能會發現, 10G switch 似乎沒有想像中的可靠!原因就讓我們看下去!

1、環境架構與問題

鳥哥所在的場域中,因為有 5 間電腦教室以及一間伺服器機房,其中機房有一台全部的電腦都會取用的 Samba 系統,這部系統裡面供應了全系四百多位師生的 windows 個人家目錄資料,以及師生們共用的教材環境,因此,您可以知道這個系統有多重要!在 2 年前,大概是在 2017 年以前, 我們使用的是 bonding 的技術,在這部系統上面安插了兩張 4 port 的 giga NIC,加上系統本身有兩個 giga port,用 10 個 giga port 搭配,組合成一個 bonding 的技術。即使如此,還是無法解決越來越重的負擔。

  • 10G 環境的設計

為此,在 2017 年以後,趁著系上有一筆教學經費,於是將整個系上教學用的骨幹網路重新設計一番! 我們採用了 10G 骨幹設計,透過兩個 12 port 的 10G switch,串連 5 間電腦教室的 router 系統,而且嚴格控制進入骨幹網路的封包, 排除 UDP 的封包,只讓 port 0~1024 以及我們系上自己的某些服務會用到的埠口,僅放行這些重要的資源,其他的封包全部禁止進入該網路! 因此,這個 10G 的環境相對的安靜,只讓系上的師生上課時,可以使用方便快捷的骨幹網路!上課重要!整體架構有點像底下這樣:

10G switch 優化

大致的設計如上圖,因為我們系上是在一個平面上,只是教室之間的距離比較遠,所以不太可能 5 間教室全部的 10G 線路都拉到一起,那太複雜了! 於是分成兩個部份,如上圖所示,左上方的 10G switch 主要連結兩間大教室 (電腦總數量約 110 台) 與 Samba server 所在的機房 (這個系統最重要), 然後右下角的 10G switch 則是連結其他三間電腦教室 (電腦總數量約 80 台),兩個 switch 之間則串接在一起而已。

至於每一間電腦教室的 router (其實我們都稱呼防火牆系統) 上面有三個網路界面:

  • 10G 界面,直接連接到 10G switch (骨幹界面)
  • 10G 界面,連接到教室內的 2 port 10G 與 24 ~ 48 port Gb switch
  • Gb 界面,直接連到對 Internet 的計中網路環境。

請看上圖的 Class A 部份,防火牆系統與骨幹是以 10G 的速度相連,與內部所有的系統則提供 10G 的速度。 而每一台學生上課用電腦則僅有 Gb 界面,但是全部的系統可以共用 10G 的速度,此外,那一部 Samba 伺服器 (最上方),則提供兩個 10G 網卡, 搭配成為 bonding 界面,假設可以提供共 20G 的流量~當然,我們知道這不可能!因為單點對單點只能使用到一張網卡! 但是在兩間教室同時使用時,則可能可以提供 20G 的流量 (只是理論上!實際上差很多)。

因為上課時,最重要的情況就是學生電腦對 Samba server 的資料傳輸,從 2017 年以來,有四個班同時上課時, 同時取用 Samba 的資料,似乎也沒有什麼太大的問題!使用上相當順暢的!

  • 網路頻寬問題的產生: scp 的速度很慢

雖然使用上沒有什麼太大的問題,但是,每學期初,我們的學生都需要將用戶端電腦進行大量的裸機復原, 也就是說,透過上圖的防火牆系統,搭配 DRBL 相關的機制,讓總數大約將近 200 台電腦,在各間教室各自的復原, 復原的動作是這樣的:

  1. 各教室都各拿一台主機來安裝多重作業系統 (一個上課用,一個考試用)
  2. 安裝系統完畢,都需要進行授課軟體的安裝、系統升級、需要環境調整等等
  3. 上課環境安裝妥當之後,透過類似 DRBL + clonezilla 環境,將上述的 Demo 環境『備份』的防火牆系統上
  4. 每一台用戶端電腦,透過類似 DRBL + clonezilla 環境,進行所有電腦的裸機復原。

乍看之下這樣很順暢啊~都沒有問題!確實,第 3 步驟上傳到防火牆系統速度是正常的,但是,我們發現第 4 步驟突然變很慢, 甚至可能比以前僅有 giga 速度時還要慢的情境!學生們覺得很不可思議!畢竟是 10G 了耶!後來使用 scp 指令進行測試, 我們發現到:

  • 從 1Gb --> 10G 時,傳輸速度可以到達 100Mbytes/s !
  • 從 10G --> 1Gb 時,傳輸速度卻僅有 40Mbytes/s 以下!

原本我們猜測與 scp 複製時需要的加密機制有關 (註1),不過,由於近期來的 CPU 都有加上 AES 硬體加解密的機制, 而我們的 CPU 檢查之下,確實都有支援 AES flag,如下所示:

[root@client ~]# grep  aes /proc/cpuinfo | head -n 1
flags           : fpu vme de pse ... aes ... hwp_act_window hwp_epp

這代表使用 aes 是最佳選擇~而 CentOS 7 預設就是使用這個加密機制~因此似乎不是這個問題所致。後來 google 了許多文件, 找到資料,不是說網路現出問題,就是 switch 插錯,或者是使用 ethtool 設定網路卡速度錯誤等等,但是我們使用 ethtool 去檢查, 網卡的資訊都是對的!沒啥大問題!也就是說,我們一直無法在學期初解決這個從 10G 往 1Gb 傳送的慢速問題!

  • 暫時的解決方案

後來學生找到許多短暫的解決方案,大致上就是調降 MTU 到 1300 以下 (註2),如此一來就可以快速的使用 scp 到正常的速度。 不過,因為防火牆系統與學生端系統都需要同步調降 MTU 到 1300 以下,但是上課時,使用的 windows 環境,會主動的將 MTU 調回來, 此時,一大堆服務都沒有辦法順利的穿透防火牆系統,因此透過網路上課的老師們,大家都苦哈哈!所以,我們只能夠在複製時將 MTU 調整到 1300 左右, 當複製完畢後,就得要重新調回 1500 才行!而且網路速度還是時順時不順~總之,就是一整個怪異得很! 但只能暫時這樣處理了!

2、尋找問題的方向

基本上,問題如果定義錯誤,尋找問題的解決方案時,結果就會出現很大的困擾!

  • 1. 從 scp 著手,結果只能短暫解決問題

如前所述,一開始我們從 scp 的問題著手,去思考解決的方案。會這麼做的原因,是因為過去有太多 scp 複製速度太低的問題, 網路上 google 可以找到一大堆 (註1)~而且,會從 scp 著手,也是因為同學們要將 demo 機器的映像檔從防火牆系統上, 直接複製到學生端電腦,卻發現傳輸速度太慢有關。

因為 scp 有太多奇怪的問題,因此,鳥哥建議學生使用 NFS 搭配 tar 的資料流,直接傳輸!甚至,透過 nc 直接複製這樣! 不過,最終發現,無論是 scp 還是 NFS 還是 nc 的網路複製行為,都是慢到很靠腰!因此,最終還是透過降低 MTU 的方式, 以底下的方式直接修改 MTU ,然後在傳輸完畢後,再次的改回來。

[root@client ~]# ip link show enp8s0
3: enp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 18:31:bf:cf:c9:90 brd ff:ff:ff:ff:ff:ff

[root@client ~]# ifconfig enp8s0 mtu 1300

[root@client ~]# ip link show enp8s0
3: enp8s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1300 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 18:31:bf:cf:c9:90 brd ff:ff:ff:ff:ff:ff

這個解決方案只能短暫的解決問題,因為,如果傳輸過後,該網卡似乎無法直接將 MTU 設定回 1500,得要將該網卡 down 再 up 才行! 這造成許多的困擾~因為,我們通常都是網路連線去控制這些主機的,如果 down 之後無法 up...那就得要親自跑去主機電腦前面操作系統! 另外,如果同時有其他的服務要透過這部機器運作,那些服務 (例如 http 或者是 SNAT 之類的) 就經常無法運作,這造成電腦教室運作的很大的困擾!

  • 2. 網路卡驅動程式,結果無法解決

鳥哥的學生還做了些特別的測試,如同架構圖,他們在 Class A 教室中,用戶端電腦彼此間使用 scp 傳輸,是沒有問題的! 雙向速度都可以達到 100Mbytes/s 左右的速度,這是 Giba 的網卡差不多的速度。但是從防火牆系統傳輸到用戶端,就是有問題! 而這些網路都是直接串接到同一台 switch 上面的!因此,直覺上,就覺得應該是防火牆主機系統的網路卡驅動程式的問題。

查了一下我們的防火牆系統與 Samba server 使用的網路卡是 Intel 的 X540 AT2 雙 10G 晶片組,雖然不是頂級的卡, 不過卻也確實提供了 10G 的效能~而 CentOS 7 針對這個網路卡提供了 ixgbe 驅動程式,這個驅動程式也是 Intel 官方說的,主要的驅動程式!

[root@server ~]# lspci | grep -i ethernet
01:00.0 Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 (rev 01)
01:00.1 Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 (rev 01)

[root@server ~]# lsmod | grep ixgbe
ixgbe                 318969  0
mdio                   14073  1 ixgbe
dca                    15130  1 ixgbe
ptp                    19231  2 ixgbe,e1000e

[root@server ~]# modinfo ixgbe | grep -v '^alias'
filename:       /lib/modules/3.10.0-957.5.1.el7.x86_64/kernel/drivers/net/ethernet/intel/ixgbe/ixgbe.ko.xz
version:        5.1.0-k-rh7.6
license:        GPL
description:    Intel(R) 10 Gigabit PCI Express Network Driver
author:         Intel Corporation, <linux.nics@intel.com>
retpoline:      Y
rhelversion:    7.6
srcversion:     8A6178275DDA252CA16D17C
depends:        mdio,ptp,dca
intree:         Y
vermagic:       3.10.0-957.5.1.el7.x86_64 SMP mod_unload modversions
signer:         CentOS Linux kernel signing key
sig_key:        9D:B7:8A:D7:C3:E3:33:8C:DB:7A:0D:8A:8D:08:F8:80:B4:14:8D:5C
sig_hashalgo:   sha256
parm:           max_vfs:Maximum number of virtual functions to allocate per physical function - default is zero and maximum value is 63 (uint)
parm:           allow_unsupported_sfp:Allow unsupported and untested SFP+ modules on 82599-based adapters (uint)
parm:           debug:Debug level (0=none,...,16=all) (int)

確定了網路卡,而且驅動程式也是最新的!另外,在 parm 的部份,那個是可以額外增加的參數,那部份似乎也沒有什麼比較特別的地方! 所以,網路卡驅動程式的部份,似乎也不是造成這個傳輸問題的主因啊!

  • 3. 網卡參數的設定

如果上網查詢一下 Linux ethtool 以及相關的網路卡參數設定,就會發現有幾個常見的網卡參數 (註4), 這些參數據說有可能會影響到網路的效能,大概常見的有:

  • TCP Segmentation Offload (TSO):使用網路卡 (NIC) 的硬體功能來處理 TCP 大型封包的分割狀態
  • UDP Fragmentation Offload (UFO):使用網路卡的硬體功能來處理 UDP 大型數據的資料處理
  • Generic Segmentation Offload (GSO):使用 TCP 或 UDP 來傳送大型封包,如果網路卡沒有即時處理封包分割或拆解時, GSO 會將同樣的操作行為直接交給 NIC 的硬體處理。這個動作會延遲封包分割的情況,等到封包可以有空被處理時,才繼續下個動作。
  • Large Receive Offload (LRO):使用 TCP 協定時,所有進入主機的封包在進入 NIC 時,都會被重新組織, 以降低分割的次數為主要思考方向。大型封包可以透過驅動程式或者是 NIC 硬體進行重組。不過 LRO 都會傾向重新組織所有的輸入封包,且經常會忽略不同的表頭資料與其他封包相關的資訊, 在 IP foward (就是 NAT 或者是 bridge 的情況) 時,就可能會產生問題。因此,當 IP forward 啟動時, LRO 通常都會自動關閉的。
  • Generic Receive Offload (GRO):GRO 在進行輸入封包的重組時,會比 LRO 嚴謹,例如 GRO 會檢查 MAC 資訊, 而且也會判斷時間戳記是否相同。不過某些情況下,10G 網卡是建議關閉 GRO 的。

查看網路卡目前啟動的上述的功能,可以透過 ethtool -k 的參數來處理!例如:

[root@server ~]# ethtool -k enp1s0f0
Features for enp1s0f0:
rx-checksumming: on
tx-checksumming: on
        tx-checksum-ipv4: off [fixed]
        tx-checksum-ip-generic: on
        tx-checksum-ipv6: off [fixed]
        tx-checksum-fcoe-crc: on [fixed]
        tx-checksum-sctp: on
scatter-gather: on
        tx-scatter-gather: on
        tx-scatter-gather-fraglist: off [fixed]
tcp-segmentation-offload: on
        tx-tcp-segmentation: on
        tx-tcp-ecn-segmentation: off [fixed]
        tx-tcp6-segmentation: on
        tx-tcp-mangleid-segmentation: off
udp-fragmentation-offload: off [fixed]
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: on
highdma: on [fixed]
rx-vlan-filter: on
vlan-challenged: off [fixed]
tx-lockless: off [fixed]
netns-local: off [fixed]
tx-gso-robust: off [fixed]
tx-fcoe-segmentation: on [fixed]
tx-gre-segmentation: on
tx-ipip-segmentation: on
tx-sit-segmentation: on
tx-udp_tnl-segmentation: on
fcoe-mtu: off [fixed]
tx-nocache-copy: off
loopback: off [fixed]
rx-fcs: off [fixed]
rx-all: off
tx-vlan-stag-hw-insert: off [fixed]
rx-vlan-stag-hw-parse: off [fixed]
rx-vlan-stag-filter: off [fixed]
busy-poll: off [fixed]
tx-gre-csum-segmentation: on
tx-udp_tnl-csum-segmentation: on
tx-gso-partial: on
tx-sctp-segmentation: off [fixed]
rx-gro-hw: off [fixed]
l2-fwd-offload: off
hw-tc-offload: off
rx-udp_tunnel-port-offload: on

上表當中,出現 fixed 表示那是不能變更的參數,其他的若有 off 或 on 的情況,就能夠修改。至於修改則使用 ethtool -K 來處理! 例如,要將上表中的 gro 關閉時,可以這樣做:

[root@server ~]# ethtool -K enp1s0f0 gro off

不過,這幾個參數前前後後改了數遍,結果整個效能還是沒有什麼特別的變化!因此,似乎這個設定值也不是很重要的影響因素。

  • 4. 流量控制 flow control 的影響,應該就是主因了!

因為一直發現到 Gb --> 10G 速度為正常,但是 10G --> Gb 就不正常~鳥哥覺得很奇怪。某天在崑大的操場跑步時,一直思考這個問題主因為何? 後來突然發現,無論 10G 還是 Giga,使用的 MTU 單位都是 1500 標準的,這是什麼意思呢?這代表,如果 10G 網卡可以使用 1500 的 MTU 傳輸出 10G 的速度, 而 Giga 只能傳輸 Giga 的速度,這代表 10G 在同樣的時間內,可以傳輸更多的封包數量!

鳥哥突然就想到,giga 的速度比較慢,因此傳輸給 10G 網卡時,10G 網卡是可以負荷的,因此速度不會有問題!但是如果是 10G 傳給 Giga 呢? 因為速度太快了,所以 giga 承受不住!因此封包就會遺失,導致 TCP 需要重傳,這樣速度當然就會下降!而且下降的情況是隨機的! 突然想到這個可能的原因,因此就朝這個方向去找資料,找到了幾個可能的方向 (註5, 6)。

基本上,10G switch 是需要流量控制的!因為跟 10G port 接觸的用戶端有可能是 giga port,如果兩端保持同樣的速度,那麼 giga port 將會無法負荷! 此時,10G switch 內的 flow control 就很重要了!這個 flow control 主要會監測兩個 switch port 的速度, 當有一端的速度明顯的高於另一端時,那麼 flow control 就會通知比較快的那一端 (就是 10G port) 傳輸需要慢一點,才能夠跟 giga 接的上! 因此,兩端的速度才會相同!這樣自然就解決上述的問題!

因為一般會購買 10G switch 的環境,大部分都是相同速度的裝置串接在一起,亦即不然就是全都為 10G ,不然都是全部 giga, 此時,每個 port 的速度都相同,那自然就沒有 flow control 的需要!所以,很多的文件都叫你不要啟動 flow control。 更有趣的是,一般 switch,預設的情況就是關閉 flow control 的啦!

flow control 是需要 switch 啟動的,那麼你怎麼知道 switch 有沒有啟動 flow control 了呢?很簡單,這樣做:

# Intel 的 10G 網卡顯示的情況:
[root@server ~]# ethtool enp1s0f0
Settings for enp1s0f0:
        Supported ports: [ TP ]
        Supported link modes:   100baseT/Full
                                1000baseT/Full
                                10000baseT/Full
        Supported pause frame use: Symmetric  (硬體是否支援)
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  100baseT/Full
                                1000baseT/Full
                                10000baseT/Full
        Advertised pause frame use: Symmetric (目前的情況)
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Speed: 10000Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: on
        MDI-X: Unknown
        Supports Wake-on: d
        Wake-on: d
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: yes

# Broadcom 10G 網卡顯示的結果:
[root@server ~]# ethtool em4
Settings for em4:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Supported pause frame use: Symmetric Receive-only
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Advertised pause frame use: Symmetric Receive-only
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Link partner advertised link modes:  100baseT/Full
                                             1000baseT/Full
        Link partner advertised pause frame use: Symmetric
        Link partner advertised auto-negotiation: Yes
        Link partner advertised FEC modes: Not reported
        Speed: 1000Mb/s
        Duplex: Full
        Port: Twisted Pair
        PHYAD: 19
        Transceiver: internal
        Auto-negotiation: on
        MDI-X: Unknown
        Current message level: 0x00000000 (0)

        Link detected: yes

不同網卡展示的結果並不一樣,如果是 Intel 的 10G 卡,只會出現『Advertised pause frame use: Symmetric』, 如果出現的是『Advertised pause frame use: No』,則代表網卡與 switch 之間不支援 flow control 喔!而如果是 Broadcom 的網卡, 基本上則是出現『Link partner advertised pause frame use: Symmetric』,如果出現的是『Link partner advertised pause frame use: No』, 也是代表不支援的意思!

一般來說,如果你沒有調整過 Linux NIC 的設定,預設的網卡 flow control 是啟動的!因此,如果透過上述指令查看到結果為 No 時, 那就代表 10G switch 沒有啟動 flow control 囉!

在設定完 switch 的 flow control 之後,嘿嘿! 10G <--> Giga 雙向的流量都可以到達 100Mbytes/s (使用 scp 的狀態)! 這真是太棒了!確定是這玩意兒搞的烏龍啦!哈哈哈!

  • 5. iperf3 軟體的使用

透過 scp 雖然可以直接使用到網路的頻寬,不過,如果大量傳輸資料時,例如 10G 的流量情況底下,被讀取的檔案速度可能會卡住在硬碟 I/O 上面, 所以,透過 scp 來直接評判網路狀態,似乎是怪怪的。那怎辦?沒關係,我們可以透過 iperf3 這個軟體來處理即可!這個軟體可以簡單的在網路兩端啟動, 一邊啟動 server 模式,一邊啟動 client 模式來存取資料,就能夠自動的判斷網路頻寬了!你可以先前往底下的網站下載:

因為鳥哥使用的是 CentOS 7 的版本,因此下載的是 64 位元的版本,就是 3.1.3 那個 RPM 版本,下載後直接使用 yum install ./iperfxxx 安裝即可。 安裝完畢之後,你可以在 Server 端下達這個指令:

# 啟動 iperf3 在 Server 模式,系統會主動開啟 port 5201 喔!
[root@server ~]# iperf3 -s &
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------

# 當然,你得要放行 Port 5201 才行!
[root@server ~]# iptables -I INPUT -s 192.168.32.0/24 -p tcp --dport 5201 -j ACCEPT

接下來在 Client 端,同樣的安裝好 iperf3 軟體,然後這樣下達指令:

# 流量從 client 傳向 server 的方向:
[root@client ~]# iperf3 -c 192.168.32.254 -t 10 -i 5
Connecting to host 192.168.32.254, port 5201
[  4] local 192.168.32.1 port 46584 connected to 192.168.32.254 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-5.00   sec   568 MBytes   953 Mbits/sec    0    342 KBytes
[  4]   5.00-10.00  sec   566 MBytes   949 Mbits/sec    0    342 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  1.11 GBytes   951 Mbits/sec    0             sender
[  4]   0.00-10.00  sec  1.11 GBytes   949 Mbits/sec                  receiver

iperf Done.

相關的指令意義大致是:

  • -c Server_IP:使用 client 模式,連線到 Server 去;
  • -t 10:僅偵測 10 秒鐘
  • -i 5:每 5 秒鐘報告一次傳輸的資訊

更多的功能請自行 man iperf3 的內容。上述的功能主要是由 client 傳向 Server,在我們的案例中,就是 1Gb --> 10G 的方向, 那如果需要從 Server 傳向 client 呢?其實你沒有必要在 client 啟動為伺服器模式,可以透過 -R 來讓 Server 傳向 client 即可! 一般來說,我們的環境裡面,大部分 server 也都是在回應 client 的要求,所以使用反向操作,也沒什麼問題才對! 處理模式有點像這樣:

# 流量從 server 傳向 client 的方向:
[root@client ~]# iperf3 -c 192.168.32.254 -t 10 -i 5 -R
Connecting to host 192.168.32.254, port 5201
Reverse mode, remote host 192.168.32.254 is sending
[  4] local 192.168.32.1 port 46592 connected to 192.168.32.254 port 5201
[ ID] Interval           Transfer     Bandwidth
[  4]   0.00-5.00   sec   566 MBytes   949 Mbits/sec
[  4]   5.00-10.00  sec   566 MBytes   949 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  1.11 GBytes   952 Mbits/sec    0             sender
[  4]   0.00-10.00  sec  1.11 GBytes   950 Mbits/sec                  receiver

iperf Done.

另外,上面的測試數據為鳥哥的環境實際測試的結果,事實上,switch 的 flow control 已經啟用了!所以雙向頻寬是 OK 的啦! ^_^

3、flow control (switch and NIC)

從前一小節的分析,我們知道 10G switch 以及相關的設備,因為有涉及到不同速度的連結 (10G and Giga),所以建議所有的裝置 (switch and NIC) 都要啟用 flow control 才好!

  • 說在前面: 使用上的限制

雖然本文確實是在調校 10G 的網路效能,但是並不是適用於所有的環境!基本上,你的 10G switch 環境中, 夾雜 10G 與 giga 的網路設備時,同時你的 10G 網卡是具備 mutli queue (多重佇列) 才適用於本文的設定喔!不要隨便就設定的與鳥哥的環境相同, 對於你的網路效能,可能不會有太大的影響。但如果你的環境與鳥哥的相同 (10G 與 giga 設備串接在一起) 時,那對於效能來說, 真的有不少幫助喔!

  • 10G switch 的 flow control

因為各家的 switch 控制界面都不一樣,例如 cisco 的 switch 還得要使用 telnet 連線才能夠設計 flow control 哩! 因此,請自行尋找您家使用的 10G switch 操作手冊來處理!鳥哥這裡只拿我們環境中,使用較為便宜的全 12 port 10G switch: ZyXEL XS1920 這個產品來介紹! 順利的登入這個 switch 之後,選擇『 Basic setting 』以及『 Port Setup 』,就會出現如下的畫面:

10G switch flow control

如上圖所示,這樣所有的 port 就擁有 flow control 的機制了!相當簡單!不過,某些特別的 switch 就得要一個一個 port 去設定, 稍微複雜些~不過,為了系統效能好!還是調整一下比較妥當!另外,不是調整 10G port 就好喔!舉例來說,我們也有 HP 的 HPE 3800-24G-2XG Switch 類似型號,這種類型的 switch 有 2 個 10G port 以及數十個 giga port,所有的 port 都要啟動 flow control 才好喔!

  • Linux NIC 的 flow control 設定

網路卡的設定大部分都與 ethtool 這個指令有關~而其中與流量控制有關的參數,就是 ethtool -a 這個選項了!

[root@server ~]# ethtool -a enp1s0f0
Pause parameters for enp1s0f0:
Autonegotiate:  on
RX:             on
TX:             on

[root@client ~]# ethtool -a enp7s0
Pause parameters for enp7s0:
Autonegotiate:  on
RX:             on
TX:             on

上面的 RX 與 TX 指的是接收與傳送的流量控制~基本上,兩個都設定比較好!另外,這個項目如果你沒有更動過,預設都是 on 的! 如果你看到的是 off 時,有可能是:(1) switch 尚未啟動 flow control,(2) 網卡確實忘記啟動 flow control。那如果要強制重新啟動 flow control 時, 可以這樣做即可:

[root@client ~]# ethtool -A enp7s0 rx on tx on
rx unmodified, ignoring
tx unmodified, ignoring
no pause parameters changed, aborting

這就代表原本預設就是 on 的意思囉!如果預設是 on 卻還是顯示 off 時,那肯定就是 switch 沒有啟動 flow control 囉! 設定完畢之後,再以底下的方式做個再次確認的動作即可:

[root@client ~]# ethtool  enp7s0
Settings for enp7s0:
        Supported ports: [ TP ]
        Supported link modes:   10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Supported pause frame use: Symmetric
        Supports auto-negotiation: Yes
        Supported FEC modes: Not reported
        Advertised link modes:  10baseT/Half 10baseT/Full
                                100baseT/Half 100baseT/Full
                                1000baseT/Full
        Advertised pause frame use: Symmetric
        Advertised auto-negotiation: Yes
        Advertised FEC modes: Not reported
        Speed: Unknown!
        Duplex: Unknown! (255)
        Port: Twisted Pair
        PHYAD: 1
        Transceiver: internal
        Auto-negotiation: on
        MDI-X: off (auto)
        Supports Wake-on: pumbg
        Wake-on: g
        Current message level: 0x00000007 (7)
                               drv probe link
        Link detected: no

再次確認 Advertised pause frame 使用方式為 Symmetric 就是有 flow control 囉!另外請記得,無論是 10G 還是 giga 的網卡, 都要啟動 flow control 喔!不然,至少 giga 的網卡 rx (接收) 一定需要 flow control 的啦!

4、其他調校 (ring buffer and queue number)

不知道你跟鳥哥有沒有相同的疑問,那就是:『既然 10G 已經是加上 flow control 了,所以傳輸速度上會與 giga 速度相同,才能讓流量穩定。 那麼問題來了,當有兩個 giga 的設備同步存取 10G port 設備時,該 10G 設備能不能個別提供 giga 給兩個獨立的設備應用? 甚至於,能不能獨立提供 10 個 giga 的速度給 10 個 giga 的設備使用呢?』,還是最終速度只能剩下 1 個 giga 呢?這是鳥哥一個很大的疑問!

  • 1. 10G 對 10G 的效能測試

首先,透過前一個小節的處理,將 flow control 打開之後,使用預設的方式 (完全不動 NIC 的參數) 進行兩個 10G 網卡間的傳輸測試, 測試的結果有點像底下這樣,看起來傳輸的品質是還不賴的:

[root@client ~]# iperf3 -c 172.31.255.32 -t 10 -i 5
Connecting to host 172.31.255.32, port 5201
[  4] local 172.31.255.102 port 50358 connected to 172.31.255.32 port 5201
[ ID] Interval           Transfer     Bandwidth       Retr  Cwnd
[  4]   0.00-5.00   sec  5.45 GBytes  9.36 Gbits/sec  1564   2.87 MBytes
[  4]   5.00-10.00  sec  5.52 GBytes  9.49 Gbits/sec  576   3.03 MBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  11.0 GBytes  9.42 Gbits/sec  2140             sender
[  4]   0.00-10.00  sec  11.0 GBytes  9.42 Gbits/sec                  receiver

[root@client ~]# iperf3 -c 172.31.255.32 -t 10 -i 5 -R
Connecting to host 172.31.255.32, port 5201
Reverse mode, remote host 172.31.255.32 is sending
[  4] local 172.31.255.102 port 50362 connected to 172.31.255.32 port 5201
[ ID] Interval           Transfer     Bandwidth
[  4]   0.00-5.00   sec  5.52 GBytes  9.49 Gbits/sec
[  4]   5.00-10.00  sec  5.53 GBytes  9.49 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  11.1 GBytes  9.49 Gbits/sec    0             sender
[  4]   0.00-10.00  sec  11.0 GBytes  9.49 Gbits/sec                  receiver

雙向傳輸都可以到差不多 9.4Gbit/s 的傳輸速度,雖然不到 10G 啦!不過,有 9.5G 左右的傳輸速度,也算是相當厲害了! 而且還是雙向哩!所以,同時上傳下載,或許能夠達到 20G 左右喔!因此,10G switch 兩側同樣是 10G NIC 時, 啟動 10G switch 的 flow control,對於傳輸的頻寬來說,應該影響不很大,速度是正常沒問題的!

  • 2. 10G 對 10 個 giga 的效能測試

接下來就是我們最擔心的部份,那麼有 2 port 10G + 24 port giga 的 switch 效能到底如何? 就是本文一開始的那張圖裡面的 Class A 啦!防火牆系統使用 10G NIC 並且安插在 10G switch port 上面, 其他用戶端電腦則直接安插在 giga port 上面,使用的也是一般的 giga NIC 而已。

iperf3 的 Server <--> Client 連線通道中,只能單獨一個連線,無法兩條連線同時使用一個 port number。 所以,如果我們想要測試 10 個 giga 裝置的話,不能只使用一個埠口喔!基本上,測試環境大概是這樣:

  • Server IP 192.168.32.254,使用 10G NIC 插在 10G port 上
  • Clients IP 192.168.32.1~192.168.32.10 這十台,使用 giga NIC 插在 giga port 上
  • Server 已經將 ssh public key 安裝在那 10 台系統中了,所以可以直接透過 root 去執行指令。
  • Server 預計啟用 5201 ~ 5210 的 10 個埠口讓用戶端分別連線。

在這樣的情況下,Server 可以這樣執行 iperf3 喔:

[root@server ~]# cat start_iperf3.sh
#!/bin/bash

for i in $( seq 1 10 )
do
        port=$(( 5200 + ${i} ))
        iperf3 -s -p ${port} &
done

[root@server ~]# source start_iperf3.sh

如果要同步執行 client 下達 iperf3 有點傷腦筋,因此,透過腳本直接執行是最簡單的了! 可以這樣直接執行看看:

[root@server ~]# cat client_to_server.sh
#!/bin/bash

for i in $(seq 1 10)
do
         port=$(( 5200 + ${i} ))
         usleep 100000; ssh -f 192.168.32.${i} " iperf3 -c 192.168.32.254 -p ${port}  -t 10 -i 5 -R -f m| grep sender   &"
        #usleep 100000; ssh -f 192.168.32.${i} " iperf3 -c 192.168.32.254 -p ${port}  -t 10 -i 5    -f m| grep receiver &"
done

[root@server ~]# sh client_to_server.sh

鳥哥測試過,如果沒有加上 usleep 時,因為每個 client 都同時跑去跟 server 要資料,此時可能會造成網路稍微擁塞,因此效能一直不太好。 所以,透過每 0.1 秒才執行一個連線,效能會稍微好些。至於兩行測試,一個是執行 10 個 client 傳送資料給 server,一個是執行 server 傳送 10 個資料給 client, 兩者是有差異的!結果分析是這樣的:

  • 當執行 10 個 Client 傳送資料給 server 時,以 Server 10G NIC 的角色來看,此時是『接收 (receiver) 』的行為, 無論怎麼執行腳本 (有沒有加上 usleep 都無關),整體的頻寬都可以到達 9.5G 以上!是接近到 10G 的效能!所以, 10G NIC 在接收 (rx) 的情境下,效能完全沒有任何影響!相當良好!
  • 當執行 10G 網卡傳送 10 個資料給 client 時,其效能很奇特!有時候僅有 4, 5G 而已,有時候可以到接近 8G,有時候只能是 3G, 效能變化相當大!此外,不論怎麼執行,全部加總的頻寬資料結果,大多是 0.95G 的倍數!也就是,如果是最佳的 8G 頻寬, 則有 4 個 client 會明顯的低於 950Mbit/s,但是這 4 個加總則大約是 2*950Mbit/s 的頻寬!另外 6 個則是完整的 950Mbit/s 的頻寬使用!

以 10G 網卡的角度來看,接收資料是沒有問題 (rx),但是傳送資料則會有很大的差異產生!而且傳送資料 (tx) 總和會是 950Mbit/s 的倍數! 這個情況相當特別!有點意思!無論如何,既然接收可以到達接近 10G 的效能,沒道理傳送 (tx) 會這麼糟糕!所以,我們開始查詢資料來進行效能調校!

  • 3. 系統的整體優化 tuned 服務

早期,我們為了加強網路與磁碟效能,得要自己調整 /etc/sysctl.conf 裡面的相關資料,包括 TCP 封包的緩衝記憶體使用量、最大與優化過的緩衝記憶體資訊等, 搞到有點民不聊生...經過網路前輩們的努力,其實大家調整的方向都差不多,因此,就有個可以自動調整相關封包與磁碟 I/O 資料的服務出現! 那就是 tuned 這個服務了!

如果是 CentOS 7 的環境,那麼大概這個服務在你安裝好之後就啟動了,如果是 CentOS 6 的環境,那就得要自己去安裝啟動才行。 另外,tuned 服務提供了 tuned-adm 這個指令功能,可以讓你快速的處理不同的使用情境 (註 7)。 假設你已經安裝了 tuned ,那麼可以這樣的查閱你目前的效能調整情境:

[root@server ~]# tuned-adm list
Available profiles:
- balanced                    - General non-specialized tuned profile
- desktop                     - Optimize for the desktop use-case
- latency-performance         - Optimize for deterministic performance at the cost of increased power consumption
- network-latency             - Optimize for deterministic performance at the cost of increased power consumption, focused on low latency network performance
- network-throughput          - Optimize for streaming network throughput, generally only necessary on older CPUs or 40G+ networks
- powersave                   - Optimize for low power consumption
- throughput-performance      - Broadly applicable tuning that provides excellent performance across a variety of common server workloads
- virtual-guest               - Optimize for running inside a virtual guest
- virtual-host                - Optimize for running KVM guests
Current active profile: balanced

預設會是平衡模式,如果你想要使用到網路最佳化,就可以使用底下的方式來處理:

[root@server ~]# tuned-adm profile throughput-performance
[root@server ~]# tuned-adm verify
Verfication succeeded, current system settings match the preset profile.
See tuned log file ('/var/log/tuned/tuned.log') for details.

很神奇的是,CentOS 7 的 tuned-adm 還可以告訴你哪邊的設定不太對勁~你可以持續手動去調整哩! 那如果以鳥哥的環境來看,我們的 Class A 教室內那幾部 client 端的電腦,其實是要跑虛擬機的,那你可以在那幾部機器上面使用底下的資料來修訂:

[root@client ~]# tuned-adm profile virtual-host

其他的就請自行測試囉!不過,即使這樣已經調整好整個系統的優化,不過對於 10G 網卡來說,其實 10G 傳送到 10 個 giga 的頻寬, 還是沒有辦法達到很好的效果,依舊是與之前的狀態一樣,就是斷斷續續的,時好時壞~雖然大多數時間的測試,都可以超過 6G 以上,不過, 能夠到達 8G 以上的次數還是很少!這實在是相當傷腦筋!

  • 4. 10G NIC 的網卡特徵 (lro, gro)

根據 Intel 網卡 driver 的說法 (註 3),那個 lro 以及 gro 在 router 與 bridge 有關的環境下, 最好關閉比較妥當!而我們的 10G NIC 所在的環境,就是有防火牆的 SNAT 與 DNAT 的設定情境下,做著路由相關的工作, 因此確實將這兩個網路卡特徵關閉比較好!至於用戶端的環境,就不需要進行這個動作囉!只針對 10G NIC 才需要進行!

[root@server ~]# ethtool -k enp1s0f0 | grep -i receive
generic-receive-offload: on  <==這個
large-receive-offload: off   <==這個
receive-hashing: on

[root@server ~]# ethtool -K enp1s0f0 lro off gro off

[root@server ~]# ethtool -k enp1s0f0 | grep -i receive
generic-receive-offload: off <==這個需要變化!
large-receive-offload: off
receive-hashing: on

這樣就做好了網卡的特徵規範~只是,依舊,對於 10G NIC 傳送 10 個 giga 到 client 去的動作,依舊沒有什麼特別的幫助!

  • 5. 10G NIC 的 ring buffer 設定

在追蹤一陣子的 google 討論之後,如 註 8 所找到的相關資料,發現網路卡還有個 ring 的參數可以修改! 原本系統預設的是 256 而已,不過硬體支援到 4096!不過,這個硬體支援度在各家網卡都不太一樣~所以,我們得要先來測試一下, 確定了正確的資料,再來修改。相關的觀察與設定可以使用 ethtool 來處理。同樣的,只需要在 10G NIC 端進行即可:

# 先觀察一下有多少 ring 的參數可以用:
[root@server ~]# ethtool -g enp1s0f0
Ring parameters for enp1s0f0:
Pre-set maximums:
RX:             4096
RX Mini:        0
RX Jumbo:       0
TX:             4096
Current hardware settings:
RX:             256
RX Mini:        0
RX Jumbo:       0
TX:             256

# 將設定值修改到最大!
[root@server ~]# ethtool -G enp1s0f0 rx 4096 tx 4096

這樣就設定完畢了!不過,依舊,沒有辦法處理好相關的 10G NIC 傳送 10 個 giga 的頻寬使用率!

  • 6. 10G NIC 的 queue number 設定

在查詢 10G NIC 使用 Intel 的廠牌時,發現到 註 9 這篇文章,該文章第六頁最左側最下方的幾個圓點清單項目說明中, 談到一個相當有趣的特色,他提到你要最佳化 10G 網卡時,最好需要進行:

Turn ON Receive (Rx) Multi-Queue (MQ) support (enabled by default in RHEL); Transmit (Tx) is currently limited to one queue in RHEL, SLES 11rC supports MQ Tx

意思是說,RHEL (其實就是 CentOS) 的接收預設使用多重佇列,而傳送的情況下,預設一個傳送只會使用到一個佇列的意思!這個佇列 (queue) 引起鳥哥很大的注意! 這是因為原本網路卡上面使用 ip link show 時,就會顯示網卡有個佇列長度,依據網路上面的許多文件,這個佇列長度會影響到資料的傳輸! 因此對於 10G NIC 來說,最好加大到 10000 比較好!設定的方式通常是:

[root@server ~]# ifconfig enp1s0f0 txqueuelen 10000
[root@server ~]# ip link show enp1s0f0
4: enp1s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 10000
    link/ether a0:36:9f:3e:c4:38 brd ff:ff:ff:ff:ff:ff

不過這個佇列修改很早之前就設計了!因此,沒有影響啊!但是,仔細查看上述的輸出!

[root@server ~]# ip link show enp1s0f0
4: enp1s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 10000
    link/ether a0:36:9f:3e:c4:38 brd ff:ff:ff:ff:ff:ff

果然,預設的情況下,CentOS 7 針對 10G 網卡,已經預設啟用了 mq 這個 muilti queues 的功能了!也就是說,這似乎已經是正確的啟動了相關的支援! 那麼,什麼是佇列呢?就鳥哥的認知來說,網路卡佇列的功能大概是這樣的:

  • 當有傳送的需求時,一個程序的傳送會佔用一個 queue,根據上述 Intel 文件的說明,該傳送程序只會使用一個佇列,即使該佇列已經滿了, 該程序也不會佔用其他的佇列。
  • 因為需要與 Giga 速度同步,因此,這個佇列的傳輸極限速度,就是到達 giga 而已。
  • 如果該佇列主要是傳輸到 10G 的另一個網路媒體時,則該佇列的極限速度就會達到 10G !

這樣說起來,那麼 10G NIC 的佇列可能會有多個才對!不然,與 giga 網卡接觸時,該佇列只能提供 1Giga 的速度,那就不可能提供超過 1G 的流量啊! 所以,鳥哥就朝著佇列的個數去找~最終找到 ethtool 裡面有個 -l 的參數可以查閱佇列個數喔!

[root@server ~]# ethtool -l enp1s0f0
Channel parameters for enp1s0f0:
Pre-set maximums:
RX:             0
TX:             0
Other:          1
Combined:       63
Current hardware settings:
RX:             0
TX:             0
Other:          1
Combined:       8

咦!硬體提供了 63 個可用的佇列,但是系統僅取用 8 個佇列而已!怪不得系統最大只能抓到 8G 的流量,而且老是取用了整數 giga 左右的效能! 如果 10 個用戶端的傳送,結果系統誤判使用了 6 個佇列 (有兩個佇列沒被使用) 時,則最大當然就是使用到 6G 的效能!

這時鳥哥也才知道, 為什麼透過 iperf3 去測試傳送 10 個資料給 10 個用戶端時,有的會跑完整的 1G 速度,有的則加總才是 1G 的速度!原來單獨 1G 的速度, 可能被單獨一個用戶端取用,也可能被多個用戶端共用!而在極端的環境下,每個佇列都被用到,就有 8G 的效能,如果只有 5 個佇列被使用, 那總量只能達到 5G 囉!原來如此!了解了!

既然是這樣,那麼將所有的 63 個佇列通通啟用,不就變得比較好!?OK!我們來調整一下佇列個數吧!

[root@server ~]# ethtool -L enp1s0f0 combined 63

這樣就將佇列由 8 個轉成 63 個了!此時如果重複使用 iperf3 的用戶端軟體去執行測試,就會發現,確實,流量使用會比較廣, 大部分的測試都可以到達 7G 以上,比以前從 4, 5G 到 8G 的速度來說,好上許多!而且,在極端好運的情況下, 每個用戶端都可以取得 1G 的頻寬(10 次測試會出現個 2, 3 次)。

不過,大部分的情況 (60% 左右),頻寬大致都使用到 7G 左右, 也就是說,有 2 ~ 4 個用戶端,會共用 2G 左右的頻寬,這樣雖然已經算很不錯,不過,就是損失了 20% 的效能,讓鳥哥覺得很洩氣!

  • 7. 10G NIC 的 multiq 佇列參數與 filter 分流功能設定

因為我們的環境 (最開始圖示中的 Class A) 是很固定的,教室內的電腦數量、電腦 IP 與電腦的網路連線到 switch 的線路都是固定的, 而且現在也知道 intel 的 10G NIC 擁有 63 個佇列,那麼能不能進行分流?意思是:

  • queue 1 --> client 1
  • queue 2 --> client 2
  • queue 3 --> client 3
  • queue .. --> client ..

如此一來,不就可以肯定讓每個佇列服務固定的用戶,每個用戶就可以擁有一條 10G 提供的專屬通道,那我們知道每條佇列都是 1G! 哇!如此豈不是可以得到完整的 10G 了呢?依據這個想法,於是鳥哥慢慢搜尋資料,以 multi queue 去查詢,結果找到了一堆文件 註 10, 裡面最重要的就是 linux kernel 提供的那篇 multi queue 的指引了!

tc 這個指令可以找出佇列的機制以及是否設定分流的行為,預設的情況下,執行 tc qdisc show 可以得到如下的結果:

[root@server ~]# tc qdisc show
qdisc noqueue 0: dev lo root refcnt 2
qdisc pfifo_fast 0: dev eno1 root refcnt 2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc mq 0: dev enp1s0f0 root
qdisc pfifo_fast 0: dev enp1s0f0 parent :8 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :7 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :6 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :5 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :4 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :3 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f0 parent :1 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc mq 0: dev enp1s0f1 root
qdisc pfifo_fast 0: dev enp1s0f1 parent :8 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :7 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :6 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :5 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :4 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :3 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
qdisc pfifo_fast 0: dev enp1s0f1 parent :1 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

看起來 enp1s0f0 這個主要的網卡確實就是使用 mq 的機制~但是,這個 mq 機制是系統自己處理分流的動作,而且在預設的情況下,提供了原本的 8 個佇列資訊, 雖然私底下確實可以提供所有 63 個佇列...不過這個 mq 沒辦法讓我們手動處理 IP 對應的方流喔!那怎辦?透過剛剛 Linux kernel 的文件, 我們可以使用一個名為 multiq 的佇列機制來處理!不過你得要注意:

鳥哥多次測試的經驗中,讓系統自己設定佇列分流的情況下,效能最佳的就是 mq 這個機制! 在文末的參考文獻中,也提到 mq 確實具有最佳的效能與頻寬使用率!所以,如果你不能確定你的環境當中的每個用戶, 或者是你的用戶個數超過你的佇列數,建議不要使用 multiq!否則效能反而會下降 10% 左右喔!

反過來說,如果你的環境跟鳥哥的類似,就是中間透過 10G, 1G 同時存在的 swtich 環境時,那麼使用 multiq 來分流, 可能是最佳的方案!接下來,請這樣做:

[root@server ~]# tc qdisc del dev enp1s0f0 root
[root@server ~]# tc qdisc add dev enp1s0f0 root handle 1: multiq
[root@server ~]# tc qdisc show dev enp1s0f0
qdisc multiq 1: root refcnt 65 bands 63/64   <==確實由 mq 更改為 multiq 囉!

# 將 queue 1 單獨分給 192.168.32.1 
[root@server ~]# tc filter add dev enp1s0f0 parent 1: protocol ip prio 1 u32 match ip dst 192.168.32.1 action skbedit queue_mapping 1
[root@server ~]# tc filter show dev enp1s0f0
filter parent 1: protocol ip pref 1 u32
filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 terminal flowid ??? not_in_hw
  match c0a82001/ffffffff at 16
        action order 1:  skbedit queue_mapping 1 pipe
         index 1 ref 1 bind 1

接下來,依序將 192.168.32.2 ~ 192.168.32.18 分別帶入 queue 2 ~ queue 18 ,就結束了!自此之後,每次偵測流量時, 每個用戶端幾乎具有完整的 1G 流量!雖然與 mq 相比,單獨的用戶都可以使用到接近 950Mbit/s 的頻寬, multiq 最大則約到達 930Mbit/s 而已,效能降低大約 2%~3% 左右,但是如果考量到總體的頻寬使用率, 在系統相當繁忙的情況下,整個總量反而發揮的比較好!因此,使用 multiq 所損耗的這 3% 傳輸效能,是在鳥哥可以接受的情況下。

另外,在鳥哥測試全部 18 台主機的環境下,multiq 對於頻寬的平均分配也比較好喔!畢竟每個用戶端都有獨立的佇列支援, 因此全部的用戶端就可以平均的去搶那 10G 的頻寬,如果是 mq 的情況下,那就看運氣了!運氣好的自己使用獨立的佇列,那速度就快上許多, 如果跟人家共享佇列的,例如假設有 3 個人共用一個佇列,那麼這三個人就得要慢慢的傳輸了!即使隔壁的單獨使用佇列的朋友已經下載完畢了, 這三個人在系統的 mq 佇列設定環境下,依舊無法挪動到空的佇列,就得要三個人共用 1G 哩!這實在是不合理!雖然 mq 是單獨佇列傳輸最快的...

  • 8. 嚴重問題

在完成上面的測試之後,就將設定值寫入 /etc/rc.d/rc.local 當中,以為這樣就搞定所有的事情了! 沒想到稍晚再次測試流量頻寬,卻發現 10 台流量全部變成 100Mbps 左右,足足少了 10 倍!鳥哥以為同時間有其他夥伴在測試, 但是使用 tcpdump 去檢查,沒有發現大量封包喔!之後開始一台一台檢查,卻發現 18 台當中,有一台因為網路卡速度降為 100Mbps! 就因為這台降為 100Mbps,導致批次處理時,所有的封包都變成 100Mbps 了!

分析為何網路卡效能會自動降為 100Mbps 呢?這是由於 Class A 的線路比較老舊,尤其從 patch panel 連接到 switch port 的短跳線經常拔插,導致水晶頭有點脫落。因此,就造成偶而某幾台網路的效能會很爛!

以前使用的 mq 因為他的佇列使用 first in first out 的功能,並不會去分析封包,因此傳輸的速度超快!而且每個佇列都是分開獨立, 因此,有一台降速時,不會影響其他台的佇列使用。現在使用的 multiq 就不是這樣喔!因為 multiq 會去分析封包, 然後將不同的封包帶入不同的佇列。因此,若有不同速度的傳輸,那該網卡就可能會使用最低速的傳輸,作為整體的傳輸動作! 所以,只要使用到該台 100Mbps 的系統,整個網卡的效能就被卡死了...

雖然要使用 100Mbps 裝置的機率幾乎是 0,但是像鳥哥這次遇到的狀態,是因為網路線材品質不良所致!這種狀況可就經常發生了! 因此,是否要使用 multiq ?還是乖一點,單純使用系統預設的 mq 即可?這可真是見仁見智! 總之,先將可能發生的問題告知您,讓大家了解一下如果遇到這個狀況,最可能的問題為何較佳!

不過,測試之後又出現了解決方案~只要設定 filter 時,指定不同的 prio 號碼即可!亦即底下的地方都需要修改!

[root@server ~]# tc filter add dev enp1s0f0 parent 1: protocol ip prio 1 u32 match ip dst 192.168.32.1 action skbedit queue_mapping 1
[root@server ~]# tc filter add dev enp1s0f0 parent 1: protocol ip prio 2 u32 match ip dst 192.168.32.2 action skbedit queue_mapping 2

似乎相同的 prio 會依據相同的速度來分配到不同的佇列的樣子~所以分開似乎就沒問題了!

5、結語與參考資料

在大約 2017 年中就有發現 10G NIC --> 1G NIC 的 scp 傳輸有點慢,大概只到 40Mbyte/s 的頻寬使用率,不過因為以前 ssh 傳輸的速度就比較慢, 因此鳥哥也不以為意。

  • 就是要解決自身的問題啊!

直到 2019 年的農曆年前一週,為了要透過 10G 傳輸資料到鳥哥的 cluster 去,卻發現傳輸時,scp 的流量僅有 5Mbytes/s 而已! 比起 40Mbytes/s 的情況還要嚴重很多!因為鳥哥辦公室使用的是 10G NIC,Cluster 內部使用的也是 10G NIC,但是 Cluster 外部使用的就是 1G NIC!這是因為 cluster 內部需要的速度比較大,而且 cluster 通常是不跟外部連線的,所以跟外部連線僅有 1G NIC 來提供基本的傳輸而已。

進一步使用 iperf3 分析這個情況,才發現 1G --> 10G 流量沒問題,產生問題的是 10G --> 1G 的情境!而且 10G --> 1G 的流量很不穩定, 有時候運氣好可以到達 600Mbyte/s,情況不好時,甚至連 100Mbytes/s 也沒辦法到達!這才讓鳥哥開始懷疑,我們的 10G 優化,是否反而是造成整體效能的低落! 所以就有這篇資料的產生!

  • 最重要的解決方案

整份文件可以參考的項目不少,但是,影響到 10G 環境中的效能最重大的參數,大概就是兩個:

  • 10G switch 與 10G NIC 的 flow control 一定要啟用!
  • 增加 10G NIC 的佇列個數到硬體最大支援個數
  • 如果有固定的用戶端 IP 環境,將 queue 的機制改成 multiq ,並且加上分流 (filter) 處置!

經過這幾個動作的修改,整個電腦教室的效能得以得到完整的發揮!而且每個用戶端幾乎具有各自的 1G queue 支援, 而且頻寬分佈相對的公平!真的不枉費 2019 年春節假期的努力啊!

  • 累死人!

其實故事沒有這麼簡單...鳥哥測試了好幾種 qdisc 機制,每種設定完畢就得要重新測試!雖然為了加速,每次測試只有 1 分鐘左右, 不過,鳥哥可以用來測試的時間也不多啊!過年期間許多拜年與家庭日總是得要顧及的~結果幾乎每天晚上都搞到 2, 3 點才去睡! 哈哈哈!

  • 參考資料:

底下的資料是鳥哥覺得比較重要的,看看大家能不能從中找到更多的好方法!

2019/02/10:春節前一週開始努力 10G NIC 調校,整個春節期間除了吃睡之外,就是在搞這個東西!相當有趣!成果很有幫助!
2019/02/13:結語的部份,竟然 10G 與 1G 的方向搞錯了!感謝網友 Yves 的告知!已經訂正了!
2019/02/10以來統計人數
計數器
   http://linux.vbird.org is designed by VBird during 2001-2017.