一、上節總結回顧
上一節,我們回顧了經典的 C10K 和 C1000K 問題。簡單回顧一下,C10K 是指如何單機同時處理 1 萬個請求(並發連接 1 萬)的問題,而 C1000K 則是單機支持處理 100 萬個
請求(並發連接 100 萬)的問題。
I/O 模型的優化,是解決 C10K 問題的最佳良方。Linux 2.6 中引入的 epoll,完美解決了C10K 的問題,並一直沿用至今。今天的很多高性能網絡方案,仍都基於 epoll。
自然,隨着互聯網技術的普及,催生出更高的性能需求。從 C10K 到 C100K,我們只需要增加系統的物理資源,就可以滿足要求;但從 C100K 到 C1000K ,光增加物理資源就不夠了。
這時,就要對系統的軟硬件進行統一優化,從硬件的中斷處理,到網絡協議棧的文件描述符數量、連接狀態跟蹤、緩存隊列,再到應用程序的工作模型等的整個網絡鏈路,都需要深入優化。
再進一步,要實現 C10M,就不是增加物理資源、調優內核和應用程序可以解決的問題了。這時內核中冗長的網絡協議棧就成了最大的負擔。
需要用 XDP 方式,在內核協議棧之前,先處理網絡包。
或基於 DPDK ,直接跳過網絡協議棧,在用戶空間通過輪詢的方式處理。
其中,DPDK 是目前最主流的高性能網絡方案,不過,這需要能支持 DPDK 的網卡配合使用。
當然,實際上,在大多數場景中,我們並不需要單機並發 1000 萬請求。通過調整系統架構,把請求分發到多台服務器中並行處理,才是更簡單、擴展性更好的方案。
不過,這種情況下,就需要我們評估系統的網絡性能,以便考察系統的處理能力,並為容量規划提供基准數據。
那么,到底該怎么評估網絡的性能呢?今天,我就帶你一起來看看這個問題。
二、性能指標回顧
在評估網絡性能前,我們先來回顧一下,衡量網絡性能的指標。在 Linux 網絡基礎篇中,我們曾經說到,帶寬、吞吐量、延時、PPS 等,都是最常用的網絡性能指標。還記得它們
的具體含義嗎?你可以先思考一下,再繼續下面的內容。
首先,帶寬,表示鏈路的最大傳輸速率,單位是 b/s(比特 / 秒)。在你為服務器選購網卡時,帶寬就是最核心的參考指標。常用的帶寬有 1000M、10G、40G、100G 等。
第二,吞吐量,表示沒有丟包時的最大數據傳輸速率,單位通常為 b/s (比特 / 秒)或者B/s(字節 / 秒)。吞吐量受帶寬的限制,吞吐量 / 帶寬也就是該網絡鏈路的使用率。
第三,延時,表示從網絡請求發出后,一直到收到遠端響應,所需要的時間延遲。這個指標在不同場景中可能會時),或者一個數據包往返所需時間(比如 RTT)。
最后,PPS,是 Packet Per Second(包 / 秒)的縮寫,表示以網絡包為單位的傳輸速率。PPS 通常用來評估網絡的轉發能力,而基於 Linux 服務器的轉發,很容易受到網絡包
大小的影響(交換機通常不會受到太大影響,即交換機可以線性轉發)。
這四個指標中,帶寬跟物理網卡配置是直接關聯的。一般來說,網卡確定后,帶寬也就確定了(當然,實際帶寬會受限於整個網絡鏈路中最小的那個模塊)。
另外,你可能在很多地方聽說過“網絡帶寬測試”,這里測試的實際上不是帶寬,而是網絡吞吐量。Linux 服務器的網絡吞吐量一般會比帶寬小,而對交換機等專門的網絡設備來
說,吞吐量一般會接近帶寬。
最后的 PPS,則是以網絡包為單位的網絡傳輸速率,通常用在需要大量轉發的場景中。而對 TCP 或者 Web 服務來說,更多會用並發連接數和每秒請求數(QPS,Query per
Second)等指標,它們更能反應實際應用程序的性能。
三、網絡基准測試
熟悉了網絡的性能指標后,接下來,我們再來看看,如何通過性能測試來確定這些指標的基准值。
你可以先思考一個問題。我們已經知道,Linux 網絡基於 TCP/IP 協議棧,而不同協議層的行為顯然不同。那么,測試之前,你應該弄清楚,你要評估的網絡性能,究竟屬於協議棧
的哪一層?換句話說,你的應用程序基於協議棧的哪一層呢?
根據前面學過的 TCP/IP 協議棧的原理,這個問題應該不難回答。比如:
- 基於 HTTP 或者 HTTPS 的 Web 應用程序,顯然屬於應用層,需要我們測試HTTP/HTTPS 的性能;
- 而對大多數游戲服務器來說,為了支持更大的同時在線人數,通常會基於 TCP 或 UDP,與客戶端進行交互,這時就需要我們測試 TCP/UDP 的性能;
- 當然,還有一些場景,是把 Linux 作為一個軟交換機或者路由器來用的。這種情況下,你更關注網絡包的處理能力(即 PPS),重點關注網絡層的轉發性能。
接下來,我就帶你從下往上,了解不同協議層的網絡性能測試方法。不過要注意,低層協議是其上的各層網絡協議的基礎。自然,低層協議的性能,也就決定了高層的網絡性能。
注意,以下所有的測試方法,都需要兩台 Linux 虛擬機。其中一台,可以當作待測試的目標機器;而另一台,則可以當作正在運行網絡服務的客戶端,用來運行測試工具。
四、各協議層的性能測試-轉發性能
我們首先來看,網絡接口層和網絡層,它們主要負責網絡包的封裝、尋址、路由以及發送和接收。在這兩個網絡協議層中,每秒可處理的網絡包數 PPS,就是最重要的性能指標。
特別是 64B 小包的處理能力,值得我們特別關注。那么,如何來測試網絡包的處理能力呢?
說到網絡包相關的測試,你可能會覺得陌生。不過,其實在專欄開頭的 CPU 性能篇中,我們就接觸過一個相關工具,也就是軟中斷案例中的 hping3。
在那個案例中,hping3 作為一個 SYN 攻擊的工具來使用。實際上, hping3 更多的用途,是作為一個測試網絡包處理能力的性能工具。
今天我再來介紹另一個更常用的工具,Linux 內核自帶的高性能網絡測試工具 pktgen。pktgen 支持豐富的自定義選項,方便你根據實際需要構造所需網絡包,從而更准確地測
試出目標服務器的性能。
不過,在 Linux 系統中,你並不能直接找到 pktgen 命令。因為 pktgen 作為一個內核線程來運行,需要你加載 pktgen 內核模塊后,再通過 /proc 文件系統來交互。下面就是
pktgen 啟動的兩個內核線程和 /proc 文件系統的交互文件:
modprobe pktgen $ ps -ef | grep pktgen | grep -v grep root 26384 2 0 06:17 ? 00:00:00 [kpktgend_0] root 26385 2 0 06:17 ? 00:00:00 [kpktgend_1] $ ls /proc/net/pktgen/ kpktgend_0 kpktgend_1 pgctrl
pktgen 在每個 CPU 上啟動一個內核線程,並可以通過 /proc/net/pktgen 下面的同名文件,跟這些線程交互;而 pgctrl 則主要用來控制這次測試的開啟和停止。
如果 modprobe 命令執行失敗,說明你的內核沒有配置 CONFIG_NET_PKTGEN 選項。這就需要你配置 pktgen 內核模塊(即 CONFIG_NET_PKTGEN=m)后,重新編譯內核,才可以使用
在使用 pktgen 測試網絡性能時,需要先給每個內核線程 kpktgend_X 以及測試網卡,配置 pktgen 選項,然后再通過 pgctrl 啟動測試。
以發包測試為例,假設發包機器使用的網卡是 eth0,而目標機器的 IP 地址為192.168.0.30,MAC 地址為 11:11:11:11:11:11。
接下來,就是一個發包測試的示例。
# 定義一個工具函數,方便后面配置各種測試選項
function pgset() {
local result
echo $1 > $PGDEV
result=`cat $PGDEV | fgrep "Result: OK:"`
if [ "$result" = "" ]; then
cat $PGDEV | fgrep Result:
fi
}
# 為 0 號線程綁定 eth0 網卡
PGDEV=/proc/net/pktgen/kpktgend_0
pgset "rem_device_all" # 清空網卡綁定
pgset "add_device eth0" # 添加 eth0 網卡
# 配置 eth0 網卡的測試選項
PGDEV=/proc/net/pktgen/eth0
pgset "count 1000000" # 總發包數量
pgset "delay 5000" # 不同包之間的發送延遲 (單位納秒)
pgset "clone_skb 0" # SKB 包復制
pgset "pkt_size 64" # 網絡包大小
pgset "dst 192.168.0.30" # 目的 IP
pgset "dst_mac 11:11:11:11:11:11" # 目的 MAC
# 啟動測試
PGDEV=/proc/net/pktgen/pgctrl
pgset "start"
稍等一會兒,測試完成后,結果可以從 /proc 文件系統中獲取。通過下面代碼段中的內容,我們可以查看剛才的測試報告:
cat /proc/net/pktgen/eth0
Params: count 1000000 min_pkt_size: 64 max_pkt_size: 64
frags: 0 delay: 0 clone_skb: 0 ifname: eth0
flows: 0 flowlen: 0
...
Current:
pkts-sofar: 1000000 errors: 0
started: 1534853256071us stopped: 1534861576098us idle: 70673us
...
Result: OK: 8320027(c8249354+d70673) usec, 1000000 (64byte,0frags)
120191pps 61Mb/sec (61537792bps) errors: 0
你可以看到,測試報告主要分為三個部分:
第一部分的 Params 是測試選項;
第二部分的 Current 是測試進度,其中, packts so far(pkts-sofar)表示已經發送了100 萬個包,也就表明測試已完成。
第三部分的 Result 是測試結果,包含測試所用時間、網絡包數量和分片、PPS、吞吐量以及錯誤數。
根據上面的結果,我們發現,PPS 為 12 萬,吞吐量為 61 Mb/s,沒有發生錯誤。那么,12 萬的 PPS 好不好呢?
實際測試代碼如下:
[root@69 ~]# modprobe pktgen
[root@69 ~]# ps -ef|grep pktgen |grep -v grep
root 1434 2 0 19:55 ? 00:00:00 [kpktgend_0]
root 1435 2 0 19:55 ? 00:00:00 [kpktgend_1]
[root@69 ~]# ls /proc/net/pktgen/
kpktgend_0 kpktgend_1 pgctrl
[root@69 ~]# function pgset() {
> local result
> echo $1 > $PGDEV
>
> result=`cat $PGDEV | fgrep "Result: OK:"`
> if [ "$result" = "" ]; then
> cat $PGDEV | fgrep Result:
> fi
> }
[root@69 ~]# PGDEV=/proc/net/pktgen/kpktgend_0
[root@69 ~]# pgset "rem_device_all" # 清空網卡綁定
[root@69 ~]# pgset "add_device eno1" # 添加 eno1 網卡
[root@69 ~]# PGDEV=/proc/net/pktgen/eno1
[root@69 ~]# pgset "count 1000000" # 總發包數量
目的 IP
pgset "dst_mac 94:18:82:0a:70:b0" # 目的 MAC
[root@69 ~]# pgset "delay 5000" # 不同包之間的發送延遲 (單位納秒)
[root@69 ~]# pgset "clone_skb 0" # SKB 包復制
[root@69 ~]# pgset "pkt_size 64" # 網絡包大小
[root@69 ~]# pgset "dst 0.0.10.42" # 目的 IP
[root@69 ~]# pgset "dst_mac 94:18:82:0a:70:b0" # 目的 MAC
[root@69 ~]# PGDEV=/proc/net/pktgen/pgctrl
[root@69 ~]# pgset "start"
[root@69 ~]# cat /proc/net/pktgen/eno1
Params: count 1000000 min_pkt_size: 64 max_pkt_size: 64
frags: 0 delay: 5000 clone_skb: 0 ifname: eno1
flows: 0 flowlen: 0
queue_map_min: 0 queue_map_max: 0
dst_min: 192.168.118.77 dst_max:
src_min: src_max:
src_mac: 00:0c:29:b2:f5:5b dst_mac: 00:0c:29:18:a9:e7
udp_src_min: 9 udp_src_max: 9 udp_dst_min: 9 udp_dst_max: 9
src_mac_count: 0 dst_mac_count: 0
Flags:
Current:
pkts-sofar: 1000000 errors: 0
started: 157688456us stopped: 252745896us idle: 81294us
seq_num: 1000001 cur_dst_mac_offset: 0 cur_src_mac_offset: 0
cur_saddr: 0x6d76a8c0 cur_daddr: 0x4d76a8c0
cur_udp_dst: 9 cur_udp_src: 9
cur_queue_map: 0
flows: 0
Result: OK: 95057439(c94976145+d81294) nsec, 1000000 (64byte,0frags)
10519pps 5Mb/sec (5385728bps) errors: 0
作為對比,你可以計算一下千兆交換機的 PPS。交換機可以達到線速(滿負載時,無差錯轉發),它的 PPS 就是 1000Mbit 除以以太網幀的大小,即 1000Mbps/((64+20)*8bit)= 1.5 Mpps
(其中 20B 為以太網幀的頭部大小)。
你看,即使是千兆交換機的 PPS,也可以達到 150 萬 PPS,比我們測試得到的 12 萬大多了。所以,看到這個數值你並不用擔心,現在的多核服務器和萬兆網卡已經很普遍了,稍
做優化就可以達到數百萬的 PPS。而且,如果你用了上節課講到的 DPDK 或 XDP ,還能達到千萬數量級。
五、各協議層的性能測試-TCP/UDP 性能
掌握了 PPS 的測試方法,接下來,我們再來看 TCP 和 UDP 的性能測試方法。說到 TCP和 UDP 的測試,我想你已經很熟悉了,甚至可能一下子就能想到相應的測試工具,
比如iperf 或者 netperf。
特別是現在的雲計算時代,在你剛拿到一批虛擬機時,首先要做的,應該就是用 iperf ,測試一下網絡性能是否符合預期。
iperf 和 netperf 都是最常用的網絡性能測試工具,測試 TCP 和 UDP 的吞吐量。它們都以客戶端和服務器通信的方式,測試一段時間內的平均吞吐量。
接下來,我們就以 iperf 為例,看一下 TCP 性能的測試方法。目前,iperf 的最新版本為iperf3,你可以運行下面的命令來安裝:
# Ubuntu apt-get install iperf3 # CentOS yum install iperf3
然后,在目標機器上啟動 iperf 服務端:
# -s 表示啟動服務端,-i 表示匯報間隔,-p 表示監聽端口 $ iperf3 -s -i 1 -p 10000
接着,在另一台機器上運行 iperf 客戶端,運行測試:
# -c 表示啟動客戶端,192.168.0.30 為目標服務器的 IP # -b 表示目標帶寬 (單位是 bits/s) # -t 表示測試時間 # -P 表示並發數,-p 表示目標服務器監聽端口 $ iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000
實際測試代碼如下:
root@luoahong:~# iperf3 -s -i 1 -p 10000 ----------------------------------------------------------- Server listening on 10000 ----------------------------------------------------------- Accepted connection from 192.168.118.109, port 45568 [ 5] local 192.168.118.77 port 10000 connected to 192.168.118.109 port 45570 [ 7] local 192.168.118.77 port 10000 connected to 192.168.118.109 port 45572 [ ID] Interval Transfer Bandwidth [ 5] 0.00-1.00 sec 42.1 MBytes 353 Mbits/sec [ 7] 0.00-1.00 sec 40.9 MBytes 343 Mbits/sec [SUM] 0.00-1.00 sec 83.0 MBytes 696 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - ...... - - - - - - - - - - - - - - - - - - - - - - - - - [ 5] 15.00-15.06 sec 643 KBytes 94.7 Mbits/sec [ 7] 15.00-15.06 sec 1.50 MBytes 226 Mbits/sec [SUM] 15.00-15.06 sec 2.13 MBytes 321 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth [ 5] 0.00-15.06 sec 0.00 Bytes 0.00 bits/sec sender [ 5] 0.00-15.06 sec 550 MBytes 306 Mbits/sec receiver [ 7] 0.00-15.06 sec 0.00 Bytes 0.00 bits/sec sender [ 7] 0.00-15.06 sec 691 MBytes 385 Mbits/sec receiver [SUM] 0.00-15.06 sec 0.00 Bytes 0.00 bits/sec sender [SUM] 0.00-15.06 sec 1.21 GBytes 691 Mbits/sec receiver ----------------------------------------------------------- Server listening on 10000
稍等一會兒(15 秒)測試結束后,回到目標服務器,查看 iperf 的報告:
[ ID] Interval Transfer Bandwidth ... [SUM] 0.00-15.04 sec 0.00 Bytes 0.00 bits/sec sender [SUM] 0.00-15.04 sec 1.51 GBytes 860 Mbits/sec receiver
實際測試代碼如下:
[root@69 /]# iperf3 -c 192.168.118.77 -b 1G -t 15 -P 2 -p 10000 Connecting to host 192.168.118.77, port 10000 [ 4] local 192.168.118.109 port 45570 connected to 192.168.118.77 port 10000 [ 6] local 192.168.118.109 port 45572 connected to 192.168.118.77 port 10000 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 43.6 MBytes 365 Mbits/sec 0 199 KBytes [ 6] 0.00-1.00 sec 42.5 MBytes 356 Mbits/sec 0 233 KBytes [SUM] 0.00-1.00 sec 86.2 MBytes 722 Mbits/sec 0 - - - - - - - - - - - - - - - - - - - - - - - - - ...... [SUM] 13.00-14.00 sec 77.3 MBytes 649 Mbits/sec 0 - - - - - - - - - - - - - - - - - - - - - - - - - [ 4] 14.00-15.00 sec 21.5 MBytes 180 Mbits/sec 0 420 KBytes [ 6] 14.00-15.00 sec 57.5 MBytes 482 Mbits/sec 0 1.13 MBytes [SUM] 14.00-15.00 sec 79.0 MBytes 663 Mbits/sec 0 - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-15.00 sec 552 MBytes 309 Mbits/sec 52 sender [ 4] 0.00-15.00 sec 550 MBytes 307 Mbits/sec receiver [ 6] 0.00-15.00 sec 692 MBytes 387 Mbits/sec 21 sender [ 6] 0.00-15.00 sec 691 MBytes 386 Mbits/sec receiver [SUM] 0.00-15.00 sec 1.21 GBytes 696 Mbits/sec 73 sender [SUM] 0.00-15.00 sec 1.21 GBytes 694 Mbits/sec receiver iperf Done.
最后的 SUM 行就是測試的匯總結果,包括測試時間、數據傳輸量以及帶寬等。按照發送和接收,這一部分又分為了 sender 和 receiver 兩行。
從測試結果你可以看到,這台機器 TCP 接收的帶寬(吞吐量)為 860 Mb/s, 跟目標的1Gb/s 相比,還是有些差距的。
六、各協議層的性能測試-HTTP 性能
傳輸層再往上,到了應用層。有的應用程序,會直接基於 TCP 或 UDP 構建服務。當然,也有大量的應用,基於應用層的協議來構建服務,HTTP 就是最常用的一個應用層協
議。比如,常用的 Apache、Nginx 等各種 Web 服務,都是基於 HTTP。
要測試 HTTP 的性能,也有大量的工具可以使用,比如 ab、webbench 等,都是常用的HTTP 壓力測試工具。其中,ab 是 Apache 自帶的 HTTP 壓測工具,主要測試 HTTP 服
務的每秒請求數、請求延遲、吞吐量以及請求延遲的分布情況等。
運行下面的命令,你就可以安裝 ab 工具:、
# Ubuntu $ apt-get install -y apache2-utils # CentOS $ yum install -y httpd-tools
接下來,在目標機器上,使用 Docker 啟動一個 Nginx 服務,然后用 ab 來測試它的性能。
首先,在目標機器上運行下面的命令:
docker run -p 80:80 -itd nginx
而在另一台機器上,運行 ab 命令,測試 Nginx 的性能:
# -c 表示並發請求數為 1000,-n 表示總的請求數為 10000
$ ab -c 1000 -n 10000 http://192.168.0.30/
...
Server Software: nginx/1.15.8
Server Hostname: 192.168.0.30
Server Port: 80
...
Requests per second: 1078.54 [#/sec] (mean)
Time per request: 927.183 [ms] (mean)
Time per request: 0.927 [ms] (mean, across all concurrent requests)
Transfer rate: 890.00 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 27 152.1 1 1038
Processing: 9 207 843.0 22 9242
Waiting: 8 207 843.0 22 9242
Total: 15 233 857.7 23 9268
Percentage of the requests served within a certain time (ms)
50% 23
66% 24
75% 24
80% 26
90% 274
95% 1195
98% 2335
99% 4663
100% 9268 (longest request)
可以看到,ab 的測試結果分為三個部分,分別是請求匯總、連接時間匯總還有請求延遲匯總。以上面的結果為例,我們具體來看。
在請求匯總部分,你可以看到:
Requests per second 為 1074; 每個請求的延遲(Time per request)分為兩行,第一行的 927 ms 表示平均延遲,包括了線程運行的調度時間和網絡請求響應時間,而下一行的 0.927ms ,則表示實際請求的響應時間; Transfer rate 表示吞吐量(BPS)為 890 KB/s。
連接時間匯總部分,則是分別展示了建立連接、請求、等待以及匯總等的各類時間,包括最小、最大、平均以及中值處理時間。
最后的請求延遲匯總部分,則給出了不同時間段內處理請求的百分比,比如, 90% 的請求,都可以在 274ms 內完成。
實際測試代碼如下:
[root@69 ~]# ab -c 1000 -n 10000 http://192.168.118.77/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.118.77 (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests
Server Software: nginx/1.17.3
Server Hostname: 192.168.118.77
Server Port: 80
Document Path: /
Document Length: 612 bytes
Concurrency Level: 1000
Time taken for tests: 10.816 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Total transferred: 8802365 bytes
HTML transferred: 6375204 bytes
Requests per second: 924.52 [#/sec] (mean)
Time per request: 1081.648 [ms] (mean)
Time per request: 1.082 [ms] (mean, across all concurrent requests)
Transfer rate: 794.72 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 3 453 132.5 469 1608
Processing: 33 579 236.1 532 2195
Waiting: 2 425 224.7 405 1781
Total: 324 1032 232.3 1026 2635
Percentage of the requests served within a certain time (ms)
50% 1026
66% 1055
75% 1073
80% 1081
90% 1105
95% 1304
98% 1952
99% 2424
100% 2635 (longest request)
七、各協議層的性能測試-應用負載性能
當你用 iperf 或者 ab 等測試工具,得到 TCP、HTTP 等的性能數據后,這些數據是否就能表示應用程序的實際性能呢?我想,你的答案應該是否定的。
比如,你的應用程序基於 HTTP 協議,為最終用戶提供一個 Web 服務。這時,使用 ab工具,可以得到某個頁面的訪問性能,但這個結果跟用戶的實際請求,很可能不一致。因
為用戶請求往往會附帶着各種各種的負載(payload),而這些負載會影響 Web 應用程序內部的處理邏輯,從而影響最終性能。
那么,為了得到應用程序的實際性能,就要求性能工具本身可以模擬用戶的請求負載,而iperf、ab 這類工具就無能為力了。幸運的是,我們還可以用 wrk、TCPCopy、Jmeter 或
者 LoadRunner 等實現這個目標。
以 wrk 為例,它是一個 HTTP 性能測試工具,內置了 LuaJIT,方便你根據實際需求,生成所需的請求負載,或者自定義響應的處理方法。
wrk 工具本身不提供 yum 或 apt 的安裝方法,需要通過源碼編譯來安裝。比如,你可以運行下面的命令,來編譯和安裝 wrk:
https://github.com/wg/wrk $ cd wrk $ apt-get install build-essential -y $ make $ sudo cp wrk /usr/local/bin/
wrk 的命令行參數比較簡單。比如,我們可以用 wrk ,來重新測一下前面已經啟動的Nginx 的性能。
# -c 表示並發連接數 1000,-t 表示線程數為 2
$ wrk -c 1000 -t 2 http://192.168.0.30/
Running 10s test @ http://192.168.0.30/
2 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 65.83ms 174.06ms 1.99s 95.85%
Req/Sec 4.87k 628.73 6.78k 69.00%
96954 requests in 10.06s, 78.59MB read
Socket errors: connect 0, read 0, write 0, timeout 179
Requests/sec: 9641.31
Transfer/sec: 7.82MB
實際測試代碼:
wrk -c 1000 -t 2 http://192.168.118.77/
[root@69 wrk]# cp wrk /usr/local/bin/
[root@69 wrk]#
[root@69 wrk]# wrk -c 1000 -t 2 http://192.168.118.77/
Running 10s test @ http://192.168.118.77/
2 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 239.20ms 67.72ms 1.72s 82.03%
Req/Sec 1.32k 516.14 3.35k 73.33%
24821 requests in 10.08s, 20.12MB read
Socket errors: connect 0, read 0, write 0, timeout 39
Requests/sec: 2463.54
Transfer/sec: 2.00MB
這里使用 2 個線程、並發 1000 連接,重新測試了 Nginx 的性能。你可以看到,每秒請求數為 9641,吞吐量為 7.82MB,平均延遲為 65ms,比前面 ab 的測試結果要好很多。
這也說明,性能工具本身的性能,對性能測試也是至關重要的。不合適的性能工具,並不能准確測出應用程序的最佳性能。
當然,wrk 最大的優勢,是其內置的 LuaJIT,可以用來實現復雜場景的性能測試。wrk 在調用 Lua 腳本時,可以將 HTTP 請求分為三個階段,即 setup、running、done,如下圖所示:
比如,你可以在 setup 階段,為請求設置認證參數(來自於 wrk 官方示例):
-- example script that demonstrates response handling and
-- retrieving an authentication token to set on all future
-- requests
token = nil
path = "/authenticate"
request = function()
return wrk.format("GET", path)
end
response = function(status, headers, body)
if not token and status == 200 then
token = headers["X-Token"]
path = "/resource"
wrk.headers["X-Token"] = token
end
end
而在執行測試時,通過 -s 選項,執行腳本的路徑:
wrk -c 1000 -t 2 -s auth.lua http://192.168.0.30/
實際測試代碼如下:
[root@69 ~]# vim auth.lua
[root@69 ~]# wrk -c 1000 -t 2 -s auth.lua http://192.168.118.77/
Running 10s test @ http://192.168.118.77/
2 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 128.05ms 39.13ms 188.87ms 63.23%
Req/Sec 1.28k 1.05k 2.63k 66.67%
824 requests in 10.08s, 247.84KB read
Non-2xx or 3xx responses: 824
Requests/sec: 81.77
Transfer/sec: 24.59KB
wrk 需要你用 Lua 腳本,來構造請求負載。這對於大部分場景來說,可能已經足夠了 。不過,它的缺點也正是,所有東西都需要代碼來構造,並且工具本身不提供 GUI 環境。
像 Jmeter 或者 LoadRunner(商業產品),則針對復雜場景提供了腳本錄制、回放、GUI 等更豐富的功能,使用起來也更加方便。
八、小結
今天,我帶你一起回顧了網絡的性能指標,並學習快了網絡性能的評估方法
性能評估是優化網絡性能的前提,只有在你發現網絡性能瓶頸時,才需要進行網絡性能優化。根據TCP/IP協議棧的原理,不同協議層關注性能重點不完全一樣,也就是對應不同的性能測試方法比如:
- 在應用層,你可以使用 wrk、Jmeter 等模擬用戶的負載,測試應用程序的每秒請求數、處理延遲、錯誤數等;
- 而在傳輸層,則可以使用 iperf 等工具,測試 TCP 的吞吐情況;
- 再向下,你還可以用 Linux 內核自帶的 pktgen ,測試服務器的 PPS。
由於低層協議是高層協議的基礎。所以,一般情況下,我們需要從上到下,對每個協議層進行性能測試,然后根據性能測試的結果,結合 Linux 網絡協議棧的原理,找出導致性能
