这篇文章上次修改于 899 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
1 确定优化目标
具体到不同的应用中,每个指标的优化标准可能不同。
- 对于 NAT 网关,直接影响到整个数据中心的网络出入性能,需要达到或接近线性转发,PPS 是主要的性能指标。
- 对于数据库、缓存等,需要快速完成网络收发,低延迟是主要的性能指标。
- 对于 Web 服务,需同时兼顾吞吐量和延迟。
可按照协议栈的每一层进行基准测试,底层性能决定高层性能。
- 网络接口层和网络层,每秒可处理的网络包数 PPS 是重要的性能指标,可用内核自带的工具 pktgen 测试。
- 传输层,吞吐量(BPS)、连接数和延迟是重要的性能指标,可用 perf 或 iperf 测试,不过要注意测试不同网络包下的性能。
- 应用层,关注的是吞吐量(BPS)、延迟和每秒请求数等指标,可用 wrk、ab 等测试。
2 网络性能工具
2.1 根据指标查找工具
2.1.1 吞吐量(BPS)
sar 可查看网络接口的吞吐量。rxkB/s 和 txkB/s 分别是接收和发送的吞吐量,单位是 KB/ 秒。
# 数字1表示每隔1秒输出一组数据
$ sar -n DEV 1
Linux 4.15.0-1035-azure (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
2.1.2 PPS
sar 可查看网络接口的 PPS。rxpck/s 和 txpck/s 分别是接收和发送的 PPS,单位为包 / 秒。
2.1.3 连接数
# 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))
当套接字处于 Established 时:
- Recv-Q 表示套接字缓冲还没有被应用程序取走的字节数(即接收队列长度)。
- 而 Send-Q 表示还没有被远端主机确认的字节数(即发送队列长度)。
当套接字处于 Listening 时:
- Recv-Q 表示全连接队列的长度。
- 而 Send-Q 表示全连接队列的最大长度。
2.1.4 延迟
ping 通过 ICMP 测试网络延迟。
# -c3表示发送三次ICMP包后停止
$ 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
--- 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
hping3 通过 TCP 测试网络延迟。
# -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
2.1.5 连接跟踪数
$ sysctl -a | grep conntrack
net.netfilter.nf_conntrack_count = 180
net.netfilter.nf_conntrack_max = 1000
net.netfilter.nf_conntrack_buckets = 65536
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
...
- net.netfilter.nf_conntrack_count,表示当前连接跟踪数;2
- net.netfilter.nf_conntrack_max,表示最大连接跟踪数;
- net.netfilter.nf_conntrack_buckets,表示连接跟踪表的大小。
2.1.6 路由
traceroute 会在路由的每一跳发送三个包,并在收到响应后,输出往返延时。如果无响应或者响应超时(默认 5s),就会输出一个星号。
# --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
2.1.7 DNS
排查 DNS 解析问题。
$ nslookup time.geekbang.org
# 域名服务器及端口信息
Server: 114.114.114.114
Address: 114.114.114.114#53
# 非权威查询结果
Non-authoritative answer:
Name: time.geekbang.org
Address: 39.106.233.17
dig 可展示递归查询的整个过程。
# +trace表示开启跟踪查询
# +nodnssec表示禁止DNS安全扩展
$ dig +trace +nodnssec time.geekbang.org
; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> +trace +nodnssec time.geekbang.org
;; global options: +cmd
. 322086 IN NS m.root-servers.net.
. 322086 IN NS a.root-servers.net.
. 322086 IN NS i.root-servers.net.
. 322086 IN NS d.root-servers.net.
. 322086 IN NS g.root-servers.net.
. 322086 IN NS l.root-servers.net.
. 322086 IN NS c.root-servers.net.
. 322086 IN NS b.root-servers.net.
. 322086 IN NS h.root-servers.net.
. 322086 IN NS e.root-servers.net.
. 322086 IN NS k.root-servers.net.
. 322086 IN NS j.root-servers.net.
. 322086 IN NS f.root-servers.net.
;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 1340 ms
org. 172800 IN NS a0.org.afilias-nst.info.
org. 172800 IN NS a2.org.afilias-nst.info.
org. 172800 IN NS b0.org.afilias-nst.org.
org. 172800 IN NS b2.org.afilias-nst.org.
org. 172800 IN NS c0.org.afilias-nst.info.
org. 172800 IN NS d0.org.afilias-nst.org.
;; Received 448 bytes from 198.97.190.53#53(h.root-servers.net) in 708 ms
geekbang.org. 86400 IN NS dns9.hichina.com.
geekbang.org. 86400 IN NS dns10.hichina.com.
;; Received 96 bytes from 199.19.54.1#53(b0.org.afilias-nst.org) in 1833 ms
time.geekbang.org. 600 IN A 39.106.233.176
;; Received 62 bytes from 140.205.41.16#53(dns10.hichina.com) in 4 ms
2.1.8 防火墙和 NAT
配置 SNAT:
$ iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -j MASQUERADE
$ iptables -t nat -A POSTROUTING -s 192.168.0.2 -j SNAT --to-source 100.100.100.100
配置 DNAT:
$ iptables -t nat -A PREROUTING -d 100.100.100.100 -j DNAT --to-destination 192.168.0.2
查看 NAT:
$ iptables -nL -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
...
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:8080
2.1.9 抓包
$ tcpdump -nn udp port 53 or host 35.190.27.188 -w ping.pcap
-nn 表示不解析 IP 地址和端口号名称。
然后用 Wireshark 打开 ping.pcap,能以更规整的格式看到抓包内容。
2.1.10 内核协议栈跟踪
$ stap --all-modules dropwatch.stp
Monitoring for dropped packets
其中,dropwatch.stp 为用户自己写的脚本。
2.2 根据工具查指标
- ifconfig、ip:配置和查看网络接口。
- ss:查看网络连接数。
- sar:查看网络接口和网络收发情况。
- nethogs:查看进程的网络收发情况。
- iftop:查看 IP 的网络收发情况。
- ethool:查看和配置网络接口。
- conntrack:查看和管理连接跟踪情况。
- nslookup、dig:排查 DNS 解析问题。
- traceroute:查看路由并测试链路信息。
- ping、hping3:测试网络延迟。
- tcpdump:网络抓包工具。
- Wireshark:网络抓包和图形界面分析工具。
- iptables:配置管理防火墙及 NAT 规则。
- perf:剖析内核协议栈性能。
- systemtap:动态追踪内核协议栈行为。
3 网络性能优化
3.1 应用程序
从网络 I/O 角度:
- I/O 多路复用技术 epoll。
- 异步 I/O。
从进程的工作模型:
- 主进程 + 多个 work 子进程。
- 监听相同端口的多进程模型。
应用层的网络协议优化:
- 长连接取代短连接。
- 使用内存等方式缓存不常变化的数据。
- 使用 Protocol Buffer 序列化等方式压缩网络 I/O 数据量。
- 使用 DNS 缓存、预取、HTTPDNS 等方式减少 DNS 解析延迟。
3.2 套接字
调整缓冲区大小,比如:
- 增大每个套接字的缓冲区大小 net.core.optmem_tax
- 增大套接字接收缓冲区大小 net.core.rmem_max 和发送缓冲区大小 net.core.wmem_max
- 增大 TCP 接收缓冲区大小 net.ipv4.tcp_rmem 和发送缓冲区大小 net.ipv4.tcp_wmem
比如发送缓冲区大小,理想值是吞吐量 * 延迟。
套接字接口也提供了一些配置项,用来改变网络连接行为:
- 为 TCP 连接设置 TCP_NODELAY 后,可禁用 Nagle 算法。
- 为 TCP 连接开启 TCP_CORK 后,可以让小包聚合成大包后再发送。
- 使用 SO_SNDBUF 和 SO_RCVBUF,可分别调整套接字的发送和接收缓冲区大小。
3.3 传输层
请求量比较大时,可能会有大量连接处于 TIME_WAIT 状态,可采用如下措施:
- 增大处于 TIME_WAIT 状态的连接数量 net.ipv4.tcp_max_tw_buckets,并增大连接跟踪表大小 net.netfilter.nf_conntrack_max
- 减小 net.ipv4.tcp_fin_timeout 和 net.netfilter.nf_conntrack_tcp_timeout_time_wait,让系统尽快释放它们所占用的资源。
- 开启端口复用 net.ipv4.tcp_tw_reuse,这样,被 TIME_WAIT 连接占用的端口还可以用到新的连接中。
- 增大本地端口范围 net.ipv4.ip_local_port_range,可支持更多的连接,提供并发能力。
- 增大最大文件描述符数量。可用 fs.nr_open 和 fs.file_max 分别增大进程和系统的最大文件描述符数量;或在应用程序的 systemd 配置文件中配置 LimitNOFILE,设置应用程序的最大文件描述符数量。
为缓解 SYN Flood,可:
- 增大 TCP 半连接的最大数量 net.ipv4.tcp_max_syn_backlog,或者开启 TCP SYN Cookie net.ipv4.tcp_syncookies (这两个选项不可同时使用)。
- 减少 SYN_RECV 状态的连接重传 SYN + ACK 包的次数 net.ipv4.tcp_synack_tries
在长连接场景中,系统默认的 Keepalive 探测间隔和重试次数一般无法满足应用程序的性能要求,需要进行优化:
- 缩短最后一次数据包到 Keepalive 探测包的间隔时间 net.ipv4.tcp_keepalive_time
- 缩短发送 Keepalive 探测包的间隔时间 net.ipv4.tcp_keepalive_intvl
- 减少 Keepalive 探测包失败后,一直到通知应用程序前的重试次数 net.ipv4.keepalive_probes
3.4 网络层
从路由和转发角度,可调整如下内核选项:
- 在需要转发的服务器中,比如 NAT 网关或使用 Docker 时,开启 IP 转发,设置 net.ipv4.ip_forward = 1
- 调整数据包的生存周期 TTL,比如设置 net.ipv4.ip_default_ttl = 64。注意,增大该值会降低系统性能。
- 开启数据包的反向地址校验,比如设置 net.ipv4.conf.eth0.rp_filter = 1。可防止 IP 欺骗,并减少伪造 IP 带来的 DDos。
从分片的角度,主要是调整 MTU 大小。比如在使用 VXLAN、GRE 等叠加网络技术时,需调大 MTU。
从 ICMP 出发,为避免 ICMP 主机探测、ICMP Flood 等问题,可限制 ICMP 行为:
- 禁止 ICMP 协议,设置 net.ipv4.icmp_echo_ignore_all = 1
- 禁止广播 ICMP,设置 net.ipv4.icmp_echo_ignore_broadcasts = 1
3.5 链路层
网卡收到包后调用中断处理程序需要消耗大量 CPU,可将这些中断调度到不同的 CPU 上:
- 为网卡硬中断配置 CPU 亲和性(smp_affinity),或者开启 irqbalance 服务。
- 开启 RPS(Receive Packet Steering)和 RFS(Receive Flow Steering),将应用程序和软中断的处理调度到相同 CPU 上,这样就可以增加 CPU 缓存命中率,减少网络延迟。
将内核中通过软中断处理的功能卸载到网卡中,通过硬件来执行;
- TSO(TCP Segmentation Offload)和 UFO(UDP Fragmentation Offload):在 TCP/UDP 协议中直接发送大包;而 TCP 包的分段(按照 MSS 分段)和 UDP 的分片(按照 MTU 分片)功能由网卡完成。
- GSO(Generic Segmentation Offload):在网卡不支持 TSO/UFO 时,将 TCP/UDP 包的分段延迟到进入网卡前再执行。不仅可以减少 CPU 的消耗,还可在发生丢包时只重传分段后的包。
- LRO(Large Receive Offload):在接收 TCP 分段包时,由网卡将其组装合并后,再交给上层网络处理。但在需要 IP 转发的情况下,不能开启 LRO,因为多个包的头部信息不一致,LRO 合并会导致网络包的校验错误。
- GRO(Genetric Receive Offload):GRO 修复了 LRO 的缺陷,并且更为通用,同时支持 TCP 和 UDP。
- RSS(Receive Side Scaling):多队列接收,基于多个接收队列来分配网络接收进程,这样可以让多个 CPU 来处理收到的网络包。
- VXLAN 卸载:让网卡来完成 VXLAN 的组包功能。
优化网络的吞吐量:
- 开启网络接口的多队列功能。
- 增大网络接口的缓冲区大小,以及队列长度等,提高网络吞吐量(可能导致延迟增大)。
- 使用 Traffic Control 工具,为不同网络流量配置 QoS。
参考
倪鹏飞. Linux 性能优化实战.
没有评论