本文是通过学习倪朋飞老师的《Linux性能优化实战》 :怎么评估系统的网络性能?
性能指标
在评估网络性能前,我们先要,衡量网络性能的指标。在 Linux 网络基础篇, 我们曾经学习过,带宽、吞吐量、延时、PPS 等,都是最常用的网络性能指标。我们来复习一下它们的具体的含义。
- 首先,带宽,表示链路的最大传输速率,单位是 b/s(比特 / 秒)。在你为服务器选购网卡时,带宽就是最核心的参考指标。常用的带宽有 1000M、10G、40G、100G 等。
- 第二,吞吐量,表示没有丢包时的最大数据传输速率,单位通常为 b/s (比特 / 秒)或者 B/s(字节 / 秒)。吞吐量受带宽的限制,吞吐量 / 带宽也就是该网络链路的使用率。
- 第三,延时,表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。这个指 标在不同场景中可能会有不同的含义。它可以表示建立连接需要的时间(比如 TCP 握手延时),或者一个数据包往返所需时间(比如 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),重点关注网络层的转发性能。
接下来,我们就从下往上,了解不同协议层的网络性能测试方法。不过要注意,低层协议是其上的各层网络协议的基础。自然,低层协议的性能,也就决定了高层的网络性能。
各协议层的性能测试
转发性能
我们首先来看,网络接口层和网络层,它们主要负责网络包的封装、寻址、路由以及发送和接收。在这两个网络协议层中,每秒可处理的网络包数 PPS,就是最重要的性能指标。 特别是 64B 小包的处理能力,值得我们特别关注。那么,如何来测试网络包的处理能力呢?
我们使用,Linux 内核自带的高性能网络测试工具 pktgen。 pktgen 支持丰富的自定义选项,方便你根据实际需要构造所需网络包,从而更准确地测 试出目标服务器的性能。
不过,在 Linux 系统中,并不能直接找到 pktgen 命令。因为 pktgen 作为一个内核线程来运行,需要加载 pktgen 内核模块后,再通过 /proc 文件系统来交互。下面就是 pktgen 启动的两个内核线程和 /proc 文件系统的交互文件:
modprobe pktgen
ps -ef | grep pktgen| g rep-v grep 3
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 启动测试。
TCP/UDP 性能
说到 TCP 和 UDP 的测试,已经很熟悉了,甚至可能一下子就能想到相应的测试工具,比如 iperf 或者 netperf。
iperf 和 netperf 都是最常用的网络性能测试工具,测试 TCP 和 UDP 的吞吐量。它们都以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。
接下来,我们就以 iperf 为例,看一下 TCP 性能的测试方法。目前,iperf 的最新版本为 iperf3,你可以运行下面的命令来安装:
yum install iperf3
然后,在目标机器上启动 iperf 服务端:
# -s 表示启动服务端,-i 表示汇报间隔,-p 表示监听端口
iperf3 -s -i 1 -p 10000
接着,在另一台机器上运行 iperf 客户端,运行测试:
# -c 表示启动客户端,192.168.0.30 为目标服务器的 IP 2 # -b 表示目标带宽 (单位是 bits/s)
# -t 表示测试时间
# -P 表示并发数,-p 表示目标服务器监听端口
iperf3 -c 172.31.36.80 -b 10G -t 15 -P 2 -p 10000
稍等一会儿(15 秒)测试结束后,回到目标服务器,查看 iperf 的报告:
[ ID] Interval Transfer Bitrate
[ 5] 0.00-15.04 sec 1.51 GBytes 860 Mbits/sec receiver
[ 8] 0.00-15.04 sec 1.24 GBytes 709 Mbits/sec receiver
[SUM] 0.00-15.04 sec 2.75 GBytes 1.57 Gbits/sec receiver
最后的 SUM 行就是测试的汇总结果,包括测试时间、数据传输量以及带宽等。按照发送和接收,这一部分又分为了 sender 和 receiver 两行。
从测试结果你可以看到,这台机器 TCP 接收的带宽(吞吐量)为 1.57 Gb/s, 跟目标的 10Gb/s 相比,还是有些差距的。
HTTP 性能
从传输层再往上,到了应用层。有的应用程序,会直接基于 TCP 或 UDP 构建服务。当 然,也有大量的应用,基于应用层的协议来构建服务,HTTP 就是最常用的一个应用层协 议。比如,常用的 Apache、Nginx 等各种 Web 服务,都是基于 HTTP。
要测试 HTTP 的性能,也有大量的工具可以使用,比如 ab、webbench 等,都是常用的 HTTP 压力测试工具。其中,ab 是 Apache 自带的 HTTP 压测工具,主要测试 HTTP 服 务的每秒请求数、请求延迟、吞吐量以及请求延迟的分布情况等。
运行下面的命令,你就可以安装 ab 工具:
yum install -y httpd-tools
运行 ab 命令,测试 Nginx 的性能:
# -c 表示并发请求数为 1000,-n 表示总的请求数为 10000
ab -c 1000 -n 10000 http://172.31.36.80/
....
Server Software: nginx
Server Hostname: 172.31.36.80
Server Port: 80
Document Path: /
Document Length: 3196 bytes
Concurrency Level: 1000
Time taken for tests: 0.462 seconds
Complete requests: 10000
Failed requests: 4
(Connect: 0, Receive: 0, Length: 0, Exceptions: 4)
Total transferred: 34460000 bytes
HTML transferred: 31960000 bytes
Requests per second: 21634.86 [#/sec] (mean)
Time per request: 46.222 [ms] (mean)
Time per request: 0.046 [ms] (mean, across all concurrent requests)
Transfer rate: 72806.37 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 12 1.7 12 18
Processing: 5 16 8.5 15 233
Waiting: 0 13 8.4 11 230
Total: 14 28 8.6 27 247
Percentage of the requests served within a certain time (ms)
50% 27
66% 29
75% 31
80% 31
90% 34
95% 36
98% 40
99% 41
100% 247 (longest request)
可以看到,ab 的测试结果分为三个部分,分别是请求汇总、连接时间汇总还有请求延迟汇总。以上面的结果为例,我们具体来看。
在请求汇总部分,可以看到:
- Requests per second: 21634.86
- 每个请求的延迟(Time per request)分为两行,第一行的 46.222 ms 表示平均延迟,包括了线程运行的调度时间和网络请求响应时间,而下一行的 0.046 ms ,则表示实际请求 的响应时间;
- Transfer rate 表示吞吐量(BPS)为 72806.37 KB/s。
连接时间汇总部分,则是分别展示了建立连接、请求、等待以及汇总等的各类时间,包括最小、最大、平均以及中值处理时间。
最后的请求延迟汇总部分,则给出了不同时间段内处理请求的百分比,比如, 90% 的请 求,都可以在 34ms 内完成。
应用负载性能
当使用 iperf 或者 ab 等测试工具,得到 TCP、HTTP 等的性能数据后,这些数据是否就能表示应用程序的实际性能呢?我想,那肯定不是的。
比如,应用程序基于 HTTP 协议,为最终用户提供一个 Web 服务。这时,使用 ab 工具,可以得到某个页面的访问性能,但这个结果跟用户的实际请求,很可能不一致。因 为用户请求往往会附带着各种各种的负载(payload),而这些负载会影响 Web 应用程序内部的处理逻辑,从而影响最终性能。
那么,为了得到应用程序的实际性能,就要求性能工具本身可以模拟用户的请求负载,而 iperf、ab 这类工具就无能为力了。但是,我们还可以用 wrk、TCPCopy、Jmeter 或者 LoadRunner 等实现这个目标。
以 wrk 为例,它是一个 HTTP 性能测试工具,内置了 LuaJIT,方便你根据实际需求,生成所需的请求负载,或者自定义响应的处理方法。
wrk 工具本身不提供 yum 或 apt 的安装方法,需要通过源码编译来安装。
git clone https://github.com/wg/wrk.git
cd wrk
make
cp wrk /usr/local/bin/
wrk 的命令行参数比较简单。比如,我们可以用 wrk ,来重新测一下前面已经启动的 Nginx 的性能。
# -c 表示并发连接数 1000,-t 表示线程数为 2
wrk -c 1000 -t 2 http://api.tickeup.com/oss/getstsinfo/
Running 10s test @ http://api.tickeup.com/oss/getstsinfo/
2 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 286.14ms 207.38ms 1.81s 65.46%
Req/Sec 1.49k 1.16k 6.24k 77.60%
25253 requests in 10.03s, 7.60MB read
Socket errors: connect 0, read 0, write 0, timeout 315
Non-2xx or 3xx responses: 24950
Requests/sec: 2517.19
Transfer/sec: 775.54KB
这里使用 2 个线程、并发 1000 连接,测试了应用程序的性能。你可以看到,每秒请求数为 2517.19,吞吐量为 775.54KB,平均延迟为 286.14ms。
总结
性能评估是优化网络性能的前提,只有在你发现网络性能瓶颈时,才需要进行网络性能优化。根据TCP/IP 协议栈的原理,不同协议层关注的性能重点不完全一样,也就对应不同的性能测试方法。例如,
- 在应用层,你可以使用 wrk、Jmeter 等模拟用户的负载,测试应用程序的每秒请求数、 处理延迟、错误数等;
- 而在传输层,则可以使用 iperf 等工具,测试 TCP 的吞吐情况;
- 再向下,你还可以用 Linux 内核自带的 pktgen ,测试服务器的 PPS。
由于低层协议是高层协议的基础。所以,一般情况下,我们需要从上到下,对每个协议层进行性能测试,然后根据性能测试的结果,结合 Linux 网络协议栈的原理,找出导致性能瓶颈的根源,进而优化网络性能。