43.套路篇|网络性能优化的几个思路
Contents
1. 确定优化目标
虽然网络性能优化的整体目标,是降低网络延迟(如 RTT)和提高吞吐量(如 BPS 和 PPS),但具体到不同应用中,每个指标的优化标准可能会不同,优先级顺序也大相径庭。
- 网络接口层和网络层。主要负责网络包的封装、寻址、路由,以及发送和接收。
- 指标:每秒可处理的网络包数PPS
- 工具:pktgen
- 传输层TCP和UDP。负责网络传输。
- 指标:吞吐量 (BPS)、连接数以及延迟
- 工具: iperf 或 netperf
- 应用层
- 指标:吞吐量(BPS)、每秒请求数、延迟
- 工具:wrk、ab
2. 网络性能工具
3. 网络性能优化
3.1 应用程序
1. C10K和100K问题
- 从网络I/O角度,2种优化思路:
- 最常用的 I/O 多路复用技术 epoll,取代poll和select
- 使用异步 I/O。等到 I/O 完成后,系统会用事件通知的方式,告诉 应用程序结果
- 从进程的工作模型角度,2种优化思路:
- 主进程 + 多个worker子进程。(其中,主进程负责管理网络连接,而子进程负责实际的业务处理。)
- 监听到相同端口的多进程模型。(所有进程都会监听相同接口,并且开启SO_REUSEPORT选项,由内核负责,把请求负载均衡到这些监听进程中去。)
- 应用层的网络协议优化
- 使用长连接取代短连接,可以显著降低 TCP 建立连接的成本。
- 使用内存等方式,来缓存不常变化的数据,可以降低网络 I/O 次数
- Protocol Buffer 等序列化的方式,压缩网络 I/O 的数据量,可以提高应用程序的 吞吐。
- 使用 DNS 缓存、预取、HTTPDNS 等方式,减少 DNS 解析的延迟,也可以提升网络 I/O 的整体速度。
3.2 套接字
套接字可以屏蔽掉 Linux 内核中不同协议的差异,为应用程序提供统一的访问接口。每个套接字,都有一个读写缓冲区。
- 读缓冲区,缓存了远端发过来的数据。如果读缓冲区已满,就不能再接收新的数据。
- 写缓冲区,缓存了要发出去的数据。如果写缓冲区已满,应用程序的写操作就会被阻塞。
为了提高网络的吞吐量,你通常需要调整这些缓冲区的大小
3.3 传输层
传输层最重要的是TCP和UDP协议,其实主要就是对这两种协议的优化。
第一类,在请求数比较大的场景下,你可能会看到大量处于 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。提高并发
- 增加最大文件描述符的数量
第二类,为了缓解 SYN FLOOD 等,利用 TCP 协议特点进行攻击而引发的性能问题,你 可以考虑优化与 SYN 状态相关的内核选项
- 增大 TCP 半连接的最大数量 net.ipv4.tcp_max_syn_backlog ,或者开启 TCP SYN Cookies net.ipv4.tcp_syncookies ,来绕开半连接数量限制的问题
- 减少 SYN_RECV 状态的连接重传 SYN+ACK 包的次数 net.ipv4.tcp_synack_retries。
第三类,在长连接的场景中,通常使用 Keepalive 来检测 TCP 连接的状态,以便对端连 接断开后,可以自动回收。系统默认的 Keepalive 探测间隔和重试次数,一般都无 法满足应用程序的性能要求。所以,这时候你需要优化与 Keepalive 相关的内核选项
- 缩短最后一次数据包到 Keepalive 探测包的间隔时间 net.ipv4.tcp_keepalive_time;
- 缩短发送 Keepalive 探测包的间隔时间 net.ipv4.tcp_keepalive_intvl;
- 减少 Keepalive 探测失败后,一直到通知应用程序前的重试次数 net.ipv4.tcp_keepalive_probes。
3.4 网络层
网络层,负责网络包的封装、寻址和路由,包括IP、ICMP等常见协议。在网络层,最主要的优化,其实就是对路由、 IP分片以及ICMP等进行调优。
第一种,从路由和转发的角度出发
- 在需要转发的服务器中,比如用作 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(Maximum Transmission Unit)的 大小。 第三种,从 ICMP 的角度出发,为了避免 ICMP 主机探测、ICMP Flood 等各种网络问 题,你可以通过内核选项,来限制 ICMP 的行为。
3.5 链路层
链路层负责网络包在物理网络中的传输,比如 MAC 寻址、错误侦测以及通过网卡传输网 络帧等。自然,链路层的优化,也是围绕这些基本功能进行的。
主要是优化网络包的收发、网络功能卸载以及网卡选项。
Author zhuyhan
LastMod 2020-07-06