Linux性能優化實戰學習筆記:第三十六講

1、上節總結回顧

上一節,咱們回顧了經典的 C10K 和 C1000K 問題。簡單回顧一下,C10K 是指如何單機同時處理 1 萬個請求(併發鏈接 1 萬)的問題,而 C1000K 則是單機支持處理 100 萬個
請求(併發鏈接 100 萬)的問題。nginx

I/O 模型的優化,是解決 C10K 問題的最佳良方。Linux 2.6 中引入的 epoll,完美解決了C10K 的問題,並一直沿用至今。今天的不少高性能網絡方案,仍都基於 epoll。git

天然,隨着互聯網技術的普及,催生出更高的性能需求。從 C10K 到 C100K,咱們只須要增長系統的物理資源,就能夠知足要求;但從 C100K 到 C1000K ,光增長物理資源就不夠了。github

這時,就要對系統的軟硬件進行統一優化,從硬件的中斷處理,到網絡協議棧的文件描述符數量、鏈接狀態跟蹤、緩存隊列,再到應用程序的工做模型等的整個網絡鏈路,都須要深刻優化。web

再進一步,要實現 C10M,就不是增長物理資源、調優內核和應用程序能夠解決的問題了。這時內核中冗長的網絡協議棧就成了最大的負擔。docker

須要用 XDP 方式,在內核協議棧以前,先處理網絡包。
或基於 DPDK ,直接跳過網絡協議棧,在用戶空間經過輪詢的方式處理。apache

其中,DPDK 是目前最主流的高性能網絡方案,不過,這須要能支持 DPDK 的網卡配合使用。vim

固然,實際上,在大多數場景中,咱們並不須要單機併發 1000 萬請求。經過調整系統架構,把請求分發到多臺服務器中並行處理,纔是更簡單、擴展性更好的方案。緩存

不過,這種狀況下,就須要咱們評估系統的網絡性能,以便考察系統的處理能力,併爲容量規劃提供基準數據。性能優化

那麼,到底該怎麼評估網絡的性能呢?今天,我就帶你一塊兒來看看這個問題。bash

2、性能指標回顧

在評估網絡性能前,咱們先來回顧一下,衡量網絡性能的指標。在 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)等指標,它們更能反應實際應用程序的性能。

3、網絡基準測試

熟悉了網絡的性能指標後,接下來,咱們再來看看,如何經過性能測試來肯定這些指標的基準值。

你能夠先思考一個問題。咱們已經知道,Linux 網絡基於 TCP/IP 協議棧,而不一樣協議層的行爲顯然不一樣。那麼,測試以前,你應該弄清楚,你要評估的網絡性能,究竟屬於協議棧
的哪一層?換句話說,你的應用程序基於協議棧的哪一層呢?

根據前面學過的 TCP/IP 協議棧的原理,這個問題應該不難回答。好比:

  1. 基於 HTTP 或者 HTTPS 的 Web 應用程序,顯然屬於應用層,須要咱們測試HTTP/HTTPS 的性能;
  2. 而對大多數遊戲服務器來講,爲了支持更大的同時在線人數,一般會基於 TCP 或 UDP,與客戶端進行交互,這時就須要咱們測試 TCP/UDP 的性能;
  3. 固然,還有一些場景,是把 Linux 做爲一個軟交換機或者路由器來用的。這種狀況下,你更關注網絡包的處理能力(即 PPS),重點關注網絡層的轉發性能。

接下來,我就帶你從下往上,瞭解不一樣協議層的網絡性能測試方法。不過要注意,低層協議是其上的各層網絡協議的基礎。天然,低層協議的性能,也就決定了高層的網絡性能。

注意,如下全部的測試方法,都須要兩臺 Linux 虛擬機。其中一臺,能夠看成待測試的目標機器;而另外一臺,則能夠看成正在運行網絡服務的客戶端,用來運行測試工具。

4、各協議層的性能測試-轉發性能

咱們首先來看,網絡接口層和網絡層,它們主要負責網絡包的封裝、尋址、路由以及發送和接收。在這兩個網絡協議層中,每秒可處理的網絡包數 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 ,還能達到千萬數量級。

5、各協議層的性能測試-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 相比,仍是有些差距的。

6、各協議層的性能測試-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)

7、各協議層的性能測試-應用負載性能

當你用 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 等更豐富的功能,使用起來也更加方便。

8、小結

今天,我帶你一塊兒回顧了網絡的性能指標,並學習快了網絡性能的評估方法

性能評估是優化網絡性能的前提,只有在你發現網絡性能瓶頸時,才須要進行網絡性能優化。根據TCP/IP協議棧的原理,不一樣協議層關注性能重點不徹底同樣,也就是對應不一樣的性能測試方法好比:

  1. 在應用層,你可使用 wrk、Jmeter 等模擬用戶的負載,測試應用程序的每秒請求數、處理延遲、錯誤數等;
  2. 而在傳輸層,則可使用 iperf 等工具,測試 TCP 的吞吐狀況;
  3. 再向下,你還能夠用 Linux 內核自帶的 pktgen ,測試服務器的 PPS。

因爲低層協議是高層協議的基礎。因此,通常狀況下,咱們須要從上到下,對每一個協議層進行性能測試,而後根據性能測試的結果,結合 Linux 網絡協議棧的原理,找出致使性能

相關文章
相關標籤/搜索