对于网络问题,比之前的都能加复杂,毕竟网络协议的各种IO模型 冗长的网络协议栈 众多的内核选项,都提高了网络的复杂性

这就需要我们针对不同网络层的性能指标来进行分析

对于网络性能优化,我们需要确定一个明确的目标,常见的目标有RTT BPS PPS,应用到不同的应用中,指标的优化标准可能不同,优化的顺序可能不同

比如对于数据库这类系统,PPS收发包这就是比较重要的性能指标

对于Web服务,则需要兼顾吞吐量和延迟

除了这两类应用程序内的分类,具体的性能协议测试,我们要使用一张图进行表示

图片

对于层次的每一层,我们都要确定其测试的基准

比如网络接口层和网络层,负责网络包的封装 寻址 路由 发送和接收,每秒可处理的网络包数 PPS,可以使用其内核自带的发包工具pktgen,测试PPS性能

UDP和TCP层,负责的是网络传输,对于其,吞吐量BPS 连接数 延迟 就是重要的性能指标,可以使用iperf netperf进行测试传输层的性能

对于应用层,则是吞吐量 BPS 每秒请求数 延迟等 可以使用wrk ab等工具进行测试应用程序性能

根据上面给出的不同层次的性能基准指标,我们可以进行相关的性能优化

常见的网络性能工具和对应的可以检测的性能,我们依旧从两个维度出发来看

第一个维度,网络性能指标来看

图片

然后从性能工具出发,利用工具看可以查看那些指标

图片

如果可以根据上述的工具定位到网络性能的瓶颈,接下来的事情,就可以水到渠成了

常见的优化思路如下,我们还是按照网络层次来进行的分类

对于应用程序,可以从网络IO的工作模型来进行优化

常见的优化思路如下

可以使用IO多路复用的技术 epoll 取代select和poll,用于解决C10K问题

更为激进的是使用AIO,来进行操作

对于进程模型,常见的为 主进程 +  多个worker子进程,主进程负责网络连接,子进程负责业务处理

还有代码中可以实现的就是

长连接代替短连接

使用内部缓存,使用Protocol Buffer来进行压缩IO包大小

使用DNS来减少DNS的解析延迟

然后是Socket层

其屏蔽了不同协议的差异,提供了统一的访问接口

内部都包含了读写缓冲区

读缓冲区,缓冲了远端数据,缓存区满了,就不能接受新的数据

写缓冲区,缓冲了要发送的数据,写缓冲区按了,应用程序也写不了

这一部分的缓冲,就是调整这些缓冲区的大小,比如

增大每个套接字的缓冲区大小 net.core.optmem_max

增大套接字接受缓冲区大小 net.core,rmem_max 和发送缓冲区大小 net.core.wmem_max

增大TCP接受缓冲区大小 net.ipv4.tcp_rmem和发送缓冲区大小 net.ipv4.tcp_wmem

整理后的结果如下

图片

tcp_rmem和tcp_wmem的三个数值为 min default max

套接字还有一些额外的配置

TCP 连接后设置TCP_NODELAY 禁用Nagle算法

TCP 连接开启TCP_CORK 让小包聚合为大包后发送

SO_SNDBUF和SO_RCVBUF,调整套接字发送缓冲区和接收缓冲区大小

过了套接字层,就是传输层,也就是TCP/UDP协议了,其优化也是对于协议的优化

TCP 的优化中,可以先考虑一些处于建立连接中中间态的优化,对于处于TIME_WAIT状态的连接,会占用内存和端口资源,优化TIME_WAIT相关的内核选项

增大处于TIME_WAIT状态连接数量 net.ipv4.tcp_max_tw_buckets,增大连接跟踪表大小 net.netfilter.nf_conntrack_max

减少 net.ipv4.tcp_fin_timeout 和 net.netfilter.nf_coontrack_tcp_timeout_time_Wait 系统尽快释放所用资源

开启端口复用,防止TIME_WAIT占用更多的端口

增大本地端口范围 net.ipv4,ip_local_port_rage

增大最大文件描述符数量 fs.nr_open和 fs.file-max

增大进程和系统最大文件描述符数量

其次是缓解SYN FLOOD,这样我们可以增大 TCP 半链接数量

减少SYN_RECV的连接重传包的次数

长连接的场景中,使用keepalive来检测TCP连接状态,以便对端连接断开后,自动回收

常见的就是缩短最后一次数据包到keepalice探测的间隔时间 net.ipv4.tcp_keepalive_time

缩短发送keepalive探测包的间隔时间,net.ipv4.tcp_keepalive_intvl

减少keepalive 探测失败后,通知应用程序之前的重试次数

net.ipv4.tcp_keepalive_probes

图片

对于TCP性能上的优化,可能在不同优化的方法上,有些冲突

UDP的优化则更加的而简单

网络包

我们看网络层的优化,主要就是IP ICMP等常见的协议,其优化就是对路由 IP ICMP等进行调优

网络层就是对于网络包的封装等调优

从路由和转发的角度来说,可以开启IP转发 net.ipv4.ip_forward = 1

调整数据包的生存周期TTL

开启数据包的反向地址校验,设置net.ipv4.conf.eth0.rp_filter = 1,防止IP欺骗

第二种,分片的角度来说,调整MTU等大小

MUTU的默认是1518B,去掉头部的18B,剩余的1500就是MTU的大小

使用VXLAN 和 GRE等网络技术,会携带更多的网络包无用数据包,比如VXLAN,就是增加了50B的报文头

我们就需要将MTU设为1550

当然,如果网络设备支持,可以设置为巨帧,提高吞吐量

还有,如果不想ICMP带来的DDOS的花,可以设置禁止一些ICMP协议,或者禁止ICMP广播

最后就是链路层,链路层的优化

其主要是负责物理网络中的传输,比如MAC寻址,错误侦测等

链路层层可以设置的主要是关于中断处理程序,需要消耗大量的CPU,所以将这些中断处理程序调度到不同的CPU,可以设置是对应的CPU亲和度

开启RPS RFS等,将应用程序和软终端的处理,调度到相同的CPU,增加CPU命中率,减少网络延迟

而且网卡都拥有很多很丰富的功能,可以在内核中进行软件处理功能,

TSO和UFO:在TCP/UDP的协议中直接发送大包,TCP和UDP的分包功能交给网卡完成

GSO: 将TCP UDP的分段,延迟到网卡前执行,减少CPU的消耗

LRO: 接收TCP分段包的时候,交由网卡进行组装合并,交给上层网络处理,IP转发的时候,不能开启

GRO:修复了LRO的缺陷

RSS:多队列接收,基于硬件的多个接收队列

VXLAN卸载,由网卡完成VXLAN的组包

网络接口本身,也有很多的方法,优化网络的吞吐量

可以开启网络接口的多队列功能,用不同的中断号,调度到不同的CPU上执行

增大网络接口的缓冲区大小,以及队列长度,提高吞吐量

使用Traffic Control工具,为不同的网络流量配置Qos

总结一下,我们梳理了常见的Linux网络性能优化

优化网络性能的同时,结合Linux的网络协议栈,从应用程序 套接字 传输层 网络层 链路层,对层次进行逐层优化

在应用程序中,优化IO模型,工作模型 应用层的网络协议

套接字层,进行套接字缓冲区的大小

传输层,优化TCP UDP协议

网络层,优化路由转发 分片和ICMP协议

链路层,优化网络包收发等

发表评论

邮箱地址不会被公开。 必填项已用*标注