网络通讯的链路为:机器A-----》路由器----〉机器B
如果我们站在本机机器作为参考物的话,应该拆分成下面三个阶段: 1.消息入口流量部分的处理流程
2.流量在本机上面的处理流程 3.流量出口流量部分的处理流程
在上面的这三个阶段,分别涉及到了不同的基础知识、工具和命令来进行诊断,笔者本篇文章按照下面的内容来整理: 1.基础知识 2.常用工具和命令 3.测试工具
一、基础知识
衡量网络性能的主要指标为:
带宽:表示链路的最大传输速率,单位是 b/s(比特 / 秒),常用的带宽有 1000M、10G、40G、100G 等。
吞吐量:表示没有丢包时的最大数据传输速率,单位通常为 b/s (比特 / 秒)或者 B/s(字节 / 秒),吞吐量受带宽的限制,吞吐量 / 带宽也就是该网络链路的使用率。
延时:表示从网络请求发出后,一直到收到远端响应,所需要的时间延迟,表示建立连接需要的时间(比如 TCP 握手延时),或者一个数据包往返所需时间(比如 RTT)。
通常,我们更常用的是双向的往返通信延迟,比如 ping 测试的结果,就是往返延时 RTT(Round-Trip Time)。除了网络延迟外,另一个常用的指标是应用程序延迟,它是指,从应用程序接收到请求,再到发回响应,全程所用的时间。应用程序延迟也指的是往返延迟,是网络数据传输时间加上数据处理时间的和。
PPS:Packet Per Second(包 / 秒)的缩写,表示以网络包为单位的传输速率。PPS 通常用来评估网络的转发能力,而基于 Linux 服务器的转发,很容易受到网络包大小的影响(交换机通常不会受到太大影响,即交换机可以线性转发)。PPS,是以网络包为单位的网络传输速率,通常用在需要大量转发的场景中。对 TCP 或者 Web 服务来说,更多会用并发连接数和每秒请求数(QPS,Query per Second)等指标,它们更能反应实际应用程序的性能。
网络的可用性(网络能否正常通信)、并发连接数(TCP 连接数量)、丢包率(丢包百分比)、重传率(重新传输的网络包比例)等也是常用的性能指标。
(备注:网络接口层和网络层,它们主要负责网络包的封装、寻址、路由以及发送和接收。在这两个网络协议层中,每秒可处理的网络包数 PPS,就是最重要的性能指标,特别是 64B 小包的处理能力,值得我们特别关注。)
1.本机内部的流量处理知识整理:
Linux 内核中的网络栈,类似于 TCP/IP 的四层结构,如下所示:
对于操作系统中的数据包收发流程,如下所示:
2.本机入口和出口流量的处理知识点整理:
1)对于机器的入口流量来说,主要涉及到的知识便是C10K、C1000K、C10M的场景处理。
C10K 、C1000K、 C10M的首字母 C 是 Client 的缩写,C10K 是单机同时处理 1 万个请求(并发连接 1 万)的问题,C1000K 是单机支持处理 100 万个请求(并发连接 100 万)的问题,C10M是1000万个请求(并发连接1000万)的问题。 1>I/O 模型的优化,特别是Linux 2.6 中引入的 epoll完美解决了 C10K 的问题。 I/O 模型相关知识参看笔者整理的下面几篇文章: https://mp.weixin.qq.com/s/_EL5gl2xfsLVUIyFyd1tyg https://mp.weixin.qq.com/s/Xi2tX3GiZfSQhod1nQmy2A
https://mp.weixin.qq.com/s/fQoHegyRO0MGnwp9ADYmSg
https://mp.weixin.qq.com/s/yB_GimOPl6o4VB85Wlh1dQ https://mp.weixin.qq.com/s/SMe8Kn4LA1aR0OrWN6I5Ww
2>从 C10K 到 C100K,我们只需要增加系统的物理资源,就可以满足要求。 3>从 C100K 到 C1000K ,光增加物理资源就不够了。这时,就要对系统的软硬件进行统一优化,从硬件的中断处理,到网络协议栈的文件描述符数量、连接状态跟踪、缓存队列,再到应用程序的工作模型等的整个网络链路,都需要深入优化。4>要实现 C10M,就不是增加物理资源、调优内核和应用程序可以解决的问题了,这时内核中冗长的网络协议栈就成了最大的负担。需要用 XDP 方式,在内核协议栈之前,先处理网络包;或基于 DPDK ,直接跳过网络协议栈,在用户空间通过轮询的方式处理。
DPDK:是用户态网络的标准,它跳过内核协议栈,直接由用户态进程通过轮询的方式,来处理网络接收。对于C10M场景,基本上每时每刻都有新的网络包需要处理,轮询的优势就很明显了。
代码语言:javascript复制1. 在 PPS 非常高的场景中,查询时间比实际工作时间少了很多,绝大部分时间都在处理网络包;
2. 跳过内核协议栈后,就省去了繁杂的硬中断、软中断再到 Linux 网络协议栈逐层处理的过程,
应用程序可以针对应用的实际场景,有针对性地优化网络包的处理逻辑,而不需要关注所有的细节。
3. DPDK 还通过大页、CPU 绑定、内存对齐、流水线并发等多种机制,优化网络包的处理效率。
(备注:DPDK 是目前最主流的高性能网络方案,不过,这需要能支持 DPDK 的网卡配合使用。)
XDP(eXpress Data Path):则是 Linux 内核提供的一种高性能网络数据路径,它允许网络包,在进入内核协议栈之前,就进行处理,也可以带来更高的性能,XDP 底层都是基于 Linux 内核的 eBPF 机制实现的。
(备注:XDP 对内核的要求比较高,需要的是 Linux 4.8 以上版本,并且它也不提供缓存队列,基于 XDP 的应用程序通常是专用的网络应用,常见的有 IDS(入侵检测系统)、DDoS 防御、 cilium 容器网络插件等。)
2) iptables 与 NAT:
NAT 技术可以重写 IP 数据包的源 IP 或者目的 IP,被普遍地用来解决公网 IP 地址短缺的问题。它的主要原理就是,网络中的多台主机,通过共享同一个公网 IP 地址,来访问外网资源,同时,由于 NAT 屏蔽了内网网络,自然也就为局域网中的机器提供了安全隔离。
NAT 的主要目的,是实现地址转换,根据实现方式的不同,NAT 可以分为三类:
代码语言:javascript复制静态 NAT,即内网 IP 与公网 IP 是一对一的永久映射关系;
动态 NAT,即内网 IP 从公网 IP 池中,动态选择一个进行映射;
网络地址端口转换 NAPT(Network Address and Port Translation),即把内网 IP 映射到公网 IP 的不同端口上,让多个内网 IP 可以共享同一个公网 IP 地址。
iptables: Linux 内核提供的 Netfilter 框架,允许对网络数据包进行修改(比如 NAT)和过滤(比如防火墙)。在这个基础上,iptables、ip6tables、ebtables 等工具,又提供了更易用的命令行接口,以便系统管理员配置和管理 NAT、防火墙的规则,其中,iptables 就是最常用的一种配置工具。 iptables详细知识点可以参考笔者的另外一篇文章:
https://mp.weixin.qq.com/s/DiW9TNuhW75oPLR9WffzkA
3. 非本机相关的网络知识: DNS(Domain Name System),即域名系统,是互联网中最基础的一项服务,主要提供域名和 IP 地址之间映射关系的查询服务。
详细知识点可以参考笔者整理的另外一篇文章: https://mp.weixin.qq.com/s/eLlGL55UoUt2HmhDWD43Sg
二、工具和命令介绍:
- 查看网络配置 ifconfig、ip
# RUNNING,LOWER_UP: 表示物理网络是连通的
# RX:receive,表示的是接收数据,从开启到现在接收封包的情况,是下行流量(Downlink)
# TX:Transmit,表示的是发送数据,从开启到现在发送封包的情况,是上行流量(Uplink)。
# errors 表示发生错误的数据包数,比如校验错误、帧同步错误等;
# dropped 表示丢弃的数据包数,即数据包已经收到了 Ring Buffer,但因为内存不足等原因丢包;
# overruns 表示超限数据包数,即网络 I/O 速度过快,导致 Ring Buffer 中的数据包来不及处理(队列满)而导致的丢包;
# carrier 表示发生 carrirer 错误的数据包数,比如双工模式不匹配、物理电缆出现问题等;
# collisions 表示碰撞数据包数。
$ ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.240.0.30 netmask 255.240.0.0 broadcast 10.255.255.255
inet6 fe80::20d:3aff:fe07:cf2a prefixlen 64 scopeid 0x20<link>
ether 78:0d:3a:07:cf:3a txqueuelen 1000 (Ethernet)
RX packets 40809142 bytes 9542369803 (9.5 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 32637401 bytes 4815573306 (4.8 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
$ ip -s addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 78:0d:3a:07:cf:3a brd ff:ff:ff:ff:ff:ff
inet 10.240.0.30/12 brd 10.255.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20d:3aff:fe07:cf2a/64 scope link
valid_lft forever preferred_lft forever
RX: bytes packets errors dropped overrun mcast
9542432350 40809397 0 0 0 193
TX: bytes packets errors dropped carrier collsns
4815625265 32637658 0 0 0 0
2. 查看套接字、网络栈、网络接口以及路由表的信息 netstat、ss
1)当套接字处于连接状态(Established):
Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。
Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)。
2)当套接字处于监听状态(Listening): Recv-Q 表示全连接队列的长度。 Send-Q 表示全连接队列的最大长度。
代码语言:javascript复制# head -n 3 表示只显示前面3行
# -l 表示只显示监听套接字
# -n 表示显示数字地址和端口(而不是名字)
# -p 表示显示进程信息
$ netstat -nlp | head -n 3
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 840/systemd-resolve
# -l 表示只显示监听套接字
# -t 表示只显示 TCP 套接字
# -n 表示显示数字地址和端口(而不是名字)
# -p 表示显示进程信息
$ ss -ltnp | head -n 3
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=840,fd=13))
LISTEN 0 128 0.0.0.0:22
0.0.0.0:* users:(("sshd",pid=1459,fd=3))
# 协议栈统计信息
$ netstat -s
#主动连接、被动连接、失败重试、发送和接收的分段数量等各种信息
...
Tcp:
3244906 active connection openings
23143 passive connection openings
115732 failed connection attempts
2964 connection resets received
1 connections established
13025010 segments received
17606946 segments sent out
44438 segments retransmitted
42 bad segments received
5315 resets sent
InCsumErrors: 42
...
$ ss -s
Total: 186 (kernel 1446)
TCP: 4 (estab 1, closed 0, orphaned 0, synrecv 0, timewait 0/0), ports 0
Transport Total IP IPv6
* 1446 - -
RAW 2 1 1
UDP 2 2 0
TCP 4 3 1
...
3. 查看系统当前的网络吞吐量和 PPS:sar
代码语言:javascript复制# 数字1表示每隔1秒输出一组数据
$ sar -n DEV 1 // -n 参数就可以查看网络的统计信息,DEV是接口
#rxpck/s 和 txpck/s 分别是接收和发送的 PPS,单位为包 / 秒。
# rxkB/s 和 txkB/s 分别是接收和发送的吞吐量,单位是 KB/ 秒。
# rxcmp/s 和 txcmp/s 分别是接收和发送的压缩数据包数,单位是包 / 秒。
# %ifutil 是网络接口的使用率,即半双工模式下为 (rxkB/s txkB/s)/Bandwidth,而全双工模式下为 max(rxkB/s, txkB/s)/Bandwidth。
Linux 4.15.0-1035 (ubuntu) 01/06/19 _x86_64_ (2 CPU)
13:21:40 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
13:21:41 eth0 18.00 20.00 5.79 4.25 0.00 0.00 0.00 0.00
13:21:41 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
13:21:41 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
Bandwidth 可以用 ethtool 来查询,它的单位通常是 Gb/s 或者 Mb/s,这里小写字母 b ,表示比特而不是字节。
代码语言:javascript复制$ ethtool eth0 | grep Speed
Speed: 1000Mb/s
4.连通性和延迟 ping
代码语言:javascript复制# -c3表示发送三次ICMP包后停止
# 第一部分,是每个 ICMP 请求的信息,包括 ICMP 序列号(icmp_seq)、TTL(生存时间,或者跳数)以及往返延时。
$ ping -c3 114.114.114.114
PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.
64 bytes from 114.114.114.114: icmp_seq=1 ttl=54 time=244 ms
64 bytes from 114.114.114.114: icmp_seq=2 ttl=47 time=244 ms
64 bytes from 114.114.114.114: icmp_seq=3 ttl=67 time=244 ms
# 第二部分,则是三次 ICMP 请求的汇总。
--- 114.114.114.114 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 244.023/244.070/244.105/0.034 ms
5.抓包工具tcpdump
安装:
代码语言:javascript复制# Ubuntu
apt-get install tcpdump wireshark
# CentOS
yum install -y tcpdump wireshark
使用介绍:
代码语言:javascript复制# -nn ,表示不解析抓包中的域名(即不反向解析)、协议以及端口号。
# udp port 53 ,表示只显示 UDP 协议的端口号(包括源端口和目的端口)为 53 的包。
# host 35.190.27.188 ,表示只显示 IP 地址(包括源地址和目的地址)为 35.190.27.188 的包。
# 这两个过滤条件中间的“ or ”,表示或的关系,也就是说,只要满足上面两个条件中的任一个,就可以展示出来。
# -w ping.pcap 表示输出到本地的ping.pcap存储起来
$ tcpdump -nn udp port 53 or host 35.190.27.188 -w ping.pcap
下载到本地机器,使用wireshark进行分析
代码语言:javascript复制$ scp host-ip/path/ping.pcap .
6.路由相关工具:mtr、route、traceroute
代码语言:javascript复制# --tcp表示使用TCP协议,-p表示端口号,-n表示不对结果中的IP地址执行反向域名解析
$ traceroute --tcp -p 80 -n baidu.com
traceroute to baidu.com (123.125.115.110), 30 hops max, 60 byte packets
1 * * *
2 * * *
3 * * *
4 * * *
5 * * *
6 * * *
7 * * *
8 * * *
9 * * *
10 * * *
11 * * *
12 * * *
13 * * *
14 123.125.115.110 20.684 ms * 20.798 ms
三、压测工具介绍
0.转发性能:hping3
网络接口层和网络层,它们主要负责网络包的封装、寻址、路由以及发送和接收,在这两个网络协议层中,每秒可处理的网络包数 PPS,就是最重要的性能指标。
hping3 可以作为一个测试网络包处理能力的性能工具。
代码语言:javascript复制# -S参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80
# -i u10表示每隔10微秒发送一个网络帧
$ hping3 -S -p 80 -i u10 192.168.0.30
(备注:Linux 内核自带的高性能网络测试工具 pktgen)
代码语言:javascript复制# -c表示发送3次请求,-S表示设置TCP SYN,-p表示端口号为80
$ hping3 -c 3 -S -p 80 baidu.com
HPING baidu.com (eth0 123.125.115.110): S set, 40 headers 0 data bytes
len=46 ip=123.125.115.110 ttl=51 id=47908 sport=80 flags=SA seq=0 win=8192 rtt=20.9 ms
len=46 ip=123.125.115.110 ttl=51 id=6788 sport=80 flags=SA seq=1 win=8192 rtt=20.9 ms
len=46 ip=123.125.115.110 ttl=51 id=37699 sport=80 flags=SA seq=2 win=8192 rtt=20.9 ms
--- baidu.com hping statistic ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 20.9/20.9/20.9 ms
1. TCP/UDP 性能:iperf 或者 netperf
iperf 和 netperf 是最常用的网络性能测试工具,测试 TCP 和 UDP 的吞吐量,它们都以客户端和服务器通信的方式,测试一段时间内的平均吞吐量。
代码语言:javascript复制# iperf 安装方式
# Ubuntu
apt-get install iperf3
# CentOS
yum install iperf3
iperf测试方式:
代码语言:javascript复制# 被测试机器上启动服务端进行
# -s表示启动服务端,-i表示汇报间隔,-p表示监听端口
$ iperf3 -s -i 1 -p 10000
测试的客户端
代码语言:javascript复制# -c表示启动客户端,192.168.0.30为目标服务器的IP
# -b表示目标带宽(单位是bits/s)
# -t表示测试时间,15 表示15秒
# -P表示并发数,-p表示目标服务器监听端口
$ iperf3 -c 192.168.0.30 -b 1G -t 15 -P 2 -p 10000
测试结果报告分析:
代码语言:javascript复制[ 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
# 吞吐量是:860 Mb/s,传递的消息量是:1.51 GBytes
2.HTTP 的性能: ab、webbench
ab 是 Apache 自带的 HTTP 压测工具,主要测试 HTTP 服务的每秒请求数、请求延迟、吞吐量以及请求延迟的分布情况等。
代码语言:javascript复制# ab的安装
# Ubuntu
$ apt-get install -y apache2-utils
# CentOS
$ yum install -y httpd-tools
目标机器上面运行被测试的服务。 客户端运行ab进行测试:
代码语言:javascript复制# -c表示并发请求数为1000,-n表示总的请求数为10000,http://192.168.0.30/ 测试的测试服务的接口
$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)
3.应用负载性能:wrk
wrk是一个 HTTP 性能测试工具,内置了 LuaJIT,方便你根据实际需求,生成所需的请求负载payload,或者自定义响应的处理方法。
安装:
代码语言:javascript复制$ https://github.com/wg/wrk
$ cd wrk
$ apt-get install build-essential -y
$ make
$ sudo cp wrk /usr/local/bin/
启动被测试服务之后,客户端运行下面的命令进行测试:
代码语言:javascript复制# -c表示并发连接数1000,-t表示线程数为2,被测试服务的接口路径:http://192.168.0.30/
$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
tcpdump 和 Wireshark 就是最常用的网络抓包和分析工具,更是分析网络性能必不可少的利器。tcpdump 仅支持命令行格式使用,常用在服务器中抓取和分析网络包。Wireshark 除了可以抓包外,还提供了强大的图形界面和汇总分析工具,在分析复杂的网络情景时,尤为简单和实用。因而,在实际分析网络性能时,先用 tcpdump 抓包,后用 Wireshark 分析,也是一种常用的方法。
参考资料:
https://blog.selectel.com/introduction-dpdk-architecture-principles/ https://www.iovisor.org/technology/xdp https://sq.sf.163.com/blog/article/200008406328934400 Linux 性能优化实战