三十六、Linux性能优化实战学习笔记-套路篇:怎么评估系统的网络性能?

简介: 三十六、Linux性能优化实战学习笔记-套路篇:怎么评估系统的网络性能?

性能指标回顾

第一,带宽,表示链路的最大传输速率,单位是 b/s(比特 / 秒)。在你为服务器选购网卡时,带宽就是最核心的参考指标。常用的带宽有 1000M、10G、40G、100G 等。


第二,吞吐量,表示没有丢包时的最大数据传输速率,单位通常为 b/s (比特 / 秒)或者 B/s(字节 / 秒)。吞吐量受带宽的限制,吞吐量 / 带宽也就是该网络链路的使用率。


第三,延时表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟。这个指标在不同场景中可能会有不同的含义。它可以表示建立连接需要的时间(比如 TCP 握手延时),或者一个数据包往返所需时间(比如 RTT)。


最后,PPS,是 Packet Per Second(包 / 秒)的缩写,表示以网络包为单位的传输速率。PPS 通常用来评估网络的转发能力,而基于 Linux 服务器的转发,很容易受到网络包大小的影响(交换机通常不会受到太大影响,即交换机可以线性转发)


你可能在很多地方听说过“网络带宽测试”,这里测试的实际上不是带宽,而是网络吞吐量。Linux 服务器的网络吞吐量一般会比带宽小,而对交换机等专门的网络设备来说,吞吐量一般会接近带宽。

什么时候用PPS?什么时候用QPS?

PPS,则是以网络包为单位的网络传输速率,通常用在需要大量转发的场景中。


对 TCP 或者 Web 服务来说,更多会用并发连接数和每秒请求数(QPS,Query per Second)等指标,它们更能反应实际应用程序的性能。

网络基准测试

评估网络性能应该弄清楚应用程序属于协议栈的哪一层

  • 基于 HTTP 或者 HTTPS 的 Web 应用程序,显然属于应用层,需要我们测试 HTTP/HTTPS 的性能;
  • 而对大多数游戏服务器来说,为了支持更大的同时在线人数,通常会基于 TCP 或 UDP ,与客户端进行交互,这时就需要我们测试 TCP/UDP 的性能;
  • 当然,还有一些场景,是把 Linux 作为一个软交换机或者路由器来用的。这种情况下,你更关注网络包的处理能力(即 PPS),重点关注网络层的转发性能。

各协议层的性能测试

网络包转发性能

网络接口层和网络层,它们主要负责网络包的封装、寻址、路由以及发送和接收。在这两个网络协议层中,每秒可处理的网络包数 PPS,就是最重要的性能指标。特别是 64B 小包的处理能力,值得我们特别关注。那么,如何来测试网络包的处理能力呢?

测试网络包处理能力的性能工具

  • hping3

hping3 作为一个 SYN 攻击的工具来使用。实际上, hping3 更多的用途,是作为一个测试网络包处理能力的性能工具。

  • pktgen

inux 内核自带的高性能网络测试工具 pktgen。pktgen 支持丰富的自定义选项,方便你根据实际需要构造所需网络包。从而更准确地测试出目标服务器的性能。


不过,在 Linux 系统中,你并不能直接找到 pktgen 命令。因为 pktgen 作为一个内核线程来运行,需要你加载 pktgen 内核模块后,再通过 /proc 文件系统来交互。下面就是 pktgen 启动的两个内核线程和 /proc 文件系统的交互文件:

[root@node100 ~]# modprobe pktgen
[root@node100 ~]# 
[root@node100 ~]# ps -ef | grep pktgen | grep -v grep
root      3910     2  0 14:25 ?        00:00:00 [kpktgend_0]
root      3911     2  0 14:25 ?        00:00:00 [kpktgend_1]
[root@node100 ~]# 
[root@node100 ~]# ls /proc/net/pktgen/
kpktgend_0  kpktgend_1  pgctrl
[root@node100 ~]# 

pktgen 在每个 CPU 上启动一个内核线程,并可以通过 /proc/net/pktgen 下面的同名文件,跟这些线程交互;而 pgctrl 则主要用来控制这次测试的开启和停止。


在使用 pktgen 测试网络性能时,需要先给每个内核线程 kpktgend_X 以及测试网卡,配置 pktgen 选项,然后再通过 pgctrl 启动测试。

测试案例

以发包测试为例,假设发包机器使用的网卡是 eth0,而目标机器的 IP 地址为 192.168.0.30,MAC 地址为 11:11:11:11:11:11。

测试脚本

#!/bin/bash
# 定义一个工具函数,方便后面配置各种测试选项
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.1.10" # 目的 IP
pgset "dst_mac 51:54:10:4d:77:**"  # 目的 MAC ip a查看
# 启动测试
PGDEV=/proc/net/pktgen/pgctrl
pgset "start"

结果可以从 /proc 文件系统中获取。通过下面代码段中的内容,我们可以查看刚才的测试报告:

[root@node100 nettest]# cat /proc/net/pktgen/eth1
Params: count 1000000  min_pkt_size: 64  max_pkt_size: 64
     frags: 0  delay: 5000  clone_skb: 0  ifname: eth1
     flows: 0 flowlen: 0
     queue_map_min: 0  queue_map_max: 0
     dst_min: 192.168.1.10  dst_max: 
     src_min:   src_max: 
     src_mac: 08:00:27:45:19:a9 dst_mac: 08:00:27:0b:87:e3
     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: 23701084929us  stopped: 23724280164us idle: 10146us
     seq_num: 1000001  cur_dst_mac_offset: 0  cur_src_mac_offset: 0
     cur_saddr: 192.168.1.9  cur_daddr: 192.168.1.10
     cur_udp_dst: 9  cur_udp_src: 9
     cur_queue_map: 0
     flows: 0
Result: OK: 23195234(c23185088+d10146) usec, 1000000 (64byte,0frags)
  43112pps 22Mb/sec (22073344bps) errors: 0

测试报告主要分为三个部分:

  • 第一部分的 Params 是测试选项;
  • 第二部分的 Current 是测试进度,其中, packts so far(pkts-sofar)表示已经发送了 100 万个包,也就表明测试已完成。
  • 第三部分的 Result 是测试结果,包含测试所用时间、网络包数量和分片、PPS、吞吐量以及错误数。


PPS 为 4万,吞吐量为 22 Mb/s,没有发生错误。那么,4 万的 PPS 好不好呢?


作为对比,你可以计算一下千兆交换机的 PPS。交换机可以达到线速(满负载时,无差错转发),它的 PPS 就是 1000Mbit 除以以太网帧的大小,即 1000Mbps/((64+20)*8bit) = 1.5 Mpps(其中,20B 为以太网帧前导和帧间距的大小)。


你看,即使是千兆交换机的 PPS,也可以达到 150 万 PPS,比我们测试得到的 4万大多了。所以,看到这个数值你并不用担心,现在的多核服务器和万兆网卡已经很普遍了,稍做优化就可以达到数百万的 PPS。而且,如果你用了上节课讲到的 DPDK 或 XDP ,还能达到千万数量级。

TCP/UDP 性能

说到 TCP 和 UDP 的测试,我想你已经很熟悉了,甚至可能一下子就能想到相应的测试工具,比如 iperf 或者 netperf。


特别是现在的云计算时代,在你刚拿到一批虚拟机时,首先要做的,应该就是用 iperf ,测试一下网络性能是否符合预期。


iperf 和 netperf 都是最常用的网络性能测试工具,测试 TCP 和 UDP 的吞吐量。它们都以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。

测试案例

在目标机器上启动 iperf 服务端

# -s 表示启动服务端,-i 表示汇报间隔,-p 表示监听端口
$ iperf3 -s -i 1 -p 10000

iperf 的最新版本为 iperf3


另一台机器上运行 iperf 客户端,运行测试,运行期间cpu软中断(si)飙升。

# -c 表示启动客户端,192.168.1.9 为目标服务器的 IP
# -b 表示目标带宽 (单位是 bits/s)
# -t 表示测试时间
# -P 表示并发数,-p 表示目标服务器监听端口
 vm]# iperf3 -c 192.168.1.9 -b 1G -t 15 -P 2 -p 10000

回到目标服务器,查看 iperf 的报告:

[ ID] Interval           Transfer     Bandwidth
[  5]   0.00-15.03  sec  0.00 Bytes  0.00 bits/sec                  sender
[  5]   0.00-15.03  sec  1.73 GBytes   991 Mbits/sec                  receiver
[  7]   0.00-15.03  sec  0.00 Bytes  0.00 bits/sec                  sender
[  7]   0.00-15.03  sec  1.39 GBytes   793 Mbits/sec                  receiver
[SUM]   0.00-15.03  sec  0.00 Bytes  0.00 bits/sec                  sender
[SUM]   0.00-15.03  sec  3.12 GBytes  1.78 Gbits/sec                  receiver

这台机器 TCP 接收的带宽(吞吐量)为 1.78Gb/s, 我的机器带宽应该是1Gb/s. 为啥还会超过呢?

6f8ab810bf184ac5b2a24651b89a4ebb.png

HTTP 性能

要测试 HTTP 的性能,也有大量的工具可以使用,比如 ab、webbench 等,都是常用的 HTTP 压力测试工具。其中,ab 是 Apache 自带的 HTTP 压测工具,主要测试 HTTP 服务的每秒请求数、请求延迟、吞吐量以及请求延迟的分布情况等。

服务端

使用 Docker 启动一个 Nginx 服务

docker run -p 80:80 -itd nginx

客户端

如果超时缩小测试参数。

-c 表示并发请求数,-n 表示总的请求数
[root@node101 opt]#  ab -c 100 -n 5000 http://192.168.1.9:80/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.1.9 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests
Server Software:        nginx/1.21.5
Server Hostname:        192.168.1.9
Server Port:            80
Document Path:          /
Document Length:        615 bytes
Concurrency Level:      100
Time taken for tests:   2.507 seconds
Complete requests:      5000
Failed requests:        0
Write errors:           0
Total transferred:      4240000 bytes
HTML transferred:       3075000 bytes
Requests per second:    1994.38 [#/sec] (mean)
Time per request:       50.141 [ms] (mean)
Time per request:       0.501 [ms] (mean, across all concurrent requests)
Transfer rate:          1651.60 [Kbytes/sec] received
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1   18   5.0     18      38
Processing:     5   31  16.0     27     115
Waiting:        2   24  14.8     21     100
Total:         20   49  16.8     45     128
Percentage of the requests served within a certain time (ms)
  50%     45
  66%     51
  75%     56
  80%     60
  90%     69
  95%     79
  98%     96
  99%    119
 100%    128 (longest request)

ab 的测试结果分为三个部分,分别是请求汇总、连接时间汇总还有请求延迟汇总。以上面的结果为例,我们具体来看。


在请求汇总部分,你可以看到:

  • Requests per second 为 1994;
  • 每个请求的延迟(Time per request)分为两行,第一行的 50ms 表示平均延迟,包括了线程运行的调度时间和网络请求响应时间,而下一行的 0.501ms ,则表示实际请求的响应时间;
  • Transfer rate 表示吞吐量(BPS)为 1651KB/s。


连接时间汇总部分,则是分别展示了建立连接、请求、等待以及汇总等的各类时间,包括最小、最大、平均以及中值处理时间。


最后的请求延迟汇总部分,则给出了不同时间段内处理请求的百分比,比如, 90% 的请求,都可以在 69ms内完成。

应用负载性能

当你用 iperf 或者 ab 等测试工具,得到 TCP、HTTP 等的性能数据后,这些数据是否就能表示应用程序的实际性能呢?我想,你的答案应该是否定的。


比如,你的应用程序基于 HTTP 协议,为最终用户提供一个 Web 服务。这时,使用 ab 工具,可以得到某个页面的访问性能,但这个结果跟用户的实际请求,很可能不一致。因为用户请求往往会附带着各种各种的负载(payload),而这些负载会影响 Web 应用程序内部的处理逻辑,从而影响最终性能。


那么,为了得到应用程序的实际性能,就要求性能工具本身可以模拟用户的请求负载,而 iperf、ab 这类工具就无能为力了。幸运的是,我们还可以用 wrk、TCPCopy、Jmeter 或者 LoadRunner 等实现这个目标。


以 wrk 为例,它是一个 HTTP 性能测试工具,内置了 LuaJIT,方便你根据实际需求,生成所需的请求负载,或者自定义响应的处理方法。

[root@node101 bin]# /usr/local/bin/wrk -c 1000 -t 2 http://192.168.1.9
Running 10s test @ http://192.168.1.9
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   151.08ms  113.62ms 732.37ms   79.64%
    Req/Sec     2.91k   712.25     5.08k    74.84%
  55161 requests in 10.05s, 44.87MB read
Requests/sec:   5488.74
Transfer/sec:      4.47MB

这里使用 2 个线程、并发 1000 连接,重新测试了 Nginx 的性能。你可以看到,每秒请求数为 5488,吞吐量为4.4MB,平均延迟为 151ms,比前面 ab 的测试结果要好很多。


这也说明,性能工具本身的性能,对性能测试也是至关重要的。不合适的性能工具,并不能准确测出应用程序的最佳性能。


当然,wrk 最大的优势,是其内置的 LuaJIT,可以用来实现复杂场景的性能测试。wrk 在调用 Lua 脚本时,可以将 HTTP 请求分为三个阶段,即 setup、running、done,如下图所示:

f436ba00ba764b318ca5ebf81a1bd221.png

可以在 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

测试结果

[root@node101 opt]# /usr/local/bin/wrk -c 1000 -s auth.lua -t 2 http://192.168.1.9
Running 10s test @ http://192.168.1.9
  2 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   122.01ms   63.73ms 339.23ms   67.60%
    Req/Sec     3.27k   551.23     5.27k    73.78%
  63553 requests in 10.07s, 18.67MB read
  Non-2xx or 3xx responses: 63553
Requests/sec:   6309.74
Transfer/sec:      1.85MB

wrk 需要你用 Lua 脚本,来构造请求负载。这对于大部分场景来说,可能已经足够了 。不过,它的缺点也正是,所有东西都需要代码来构造,并且工具本身不提供 GUI 环境。


像 Jmeter 或者 LoadRunner(商业产品),则针对复杂场景提供了脚本录制、回放、GUI 等更丰富的功能,使用起来也更加方便。

小结

今天,我带你一起回顾了网络的性能指标,并学习了网络性能的评估方法。


性能评估是优化网络性能的前提,只有在你发现网络性能瓶颈时,才需要进行网络性能优化。根据 TCP/IP 协议栈的原理,不同协议层关注的性能重点不完全一样,也就对应不同的性能测试方法。比如,

在应用层,你可以使用 wrk、Jmeter 等模拟用户的负载,测试应用程序的每秒请求数、处理延迟、错误数等;

而在传输层,则可以使用 iperf 等工具,测试 TCP 的吞吐情况;

再向下,你还可以用 Linux 内核自带的 pktgen ,测试服务器的 PPS。


由于低层协议是高层协议的基础。所以,一般情况下,我们需要从上到下,对每个协议层进行性能测试,然后根据性能测试的结果,结合 Linux 网络协议栈的原理,找出导致性能瓶颈的根源,进而优化网络性能。


相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
16天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
57 3
|
16天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
48 2
|
10天前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
15 3
|
16天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
53 3
|
19天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
36 6
|
19天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
55 6
|
Linux 开发工具 数据安全/隐私保护
阿里云linux实战体验报告
通过阿里云 linux 实战教学体验提升自我
145 1
|
15天前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
103 6
|
23天前
|
缓存 监控 Linux
|
27天前
|
Linux Shell 数据安全/隐私保护