【Performance】网络调优

Posted by 西维蜀黍 on 2020-10-14, Last Modified on 2021-11-03

Misc

查看一下网络带宽使用情况,在Linux下,你可以使用iftop, iptraf, ntop, tcpdump这些命令来查看

测试TCP的RTT时间

$ ping aaa.com
PING aaa.com (10.1.2.3) 56(84) bytes of data.
64 bytes from 10.1.2.3: icmp_seq=1 ttl=61 time=0.104 ms
64 bytes from 10.1.2.3: icmp_seq=2 ttl=61 time=0.097 ms
64 bytes from 10.1.2.3: icmp_seq=3 ttl=61 time=0.103 ms
64 bytes from 10.1.2.3: icmp_seq=4 ttl=61 time=0.116 ms
64 bytes from 10.1.2.3: icmp_seq=5 ttl=61 time=0.086 ms
64 bytes from 10.1.2.3: icmp_seq=6 ttl=61 time=0.101 ms
64 bytes from 10.1.2.3: icmp_seq=7 ttl=61 time=0.086 ms
64 bytes from 10.1.2.3: icmp_seq=8 ttl=61 time=0.095 ms
64 bytes from 10.1.2.3: icmp_seq=9 ttl=61 time=0.091 ms
64 bytes from 10.1.2.3: icmp_seq=10 ttl=61 time=0.092 ms

输出显示每个包的往返时间(round trip time,RTT)并总结各种统计信息。由于时间戳是由ping命令自己计量的,其中包括获取时间戳到处理网络 I/O 的整个 CPU 代码路径执行时间。

与应用程序协议相比,路由器可能以较低的优先级处理 ICMP 数据包,因而延时可能比通常情况下有更高的波动。

sar -n DEV

  • -n DEV***:***网络接口统计信息。
  • -n EDEV***:***网络接口错误。
  • -n IP***:***IP 数据报统计信息。
  • -n EIP***:***IP 错误统计信息。
  • -n TCP***:***TCP 统计信息。
  • -n ETCP***:***TCP 错误统计信息。
  • -n SOCK***:***套接字使用。

提供的统计信息见下表。

选项 统计信息 描述 单位
-n DEV rxpkg/s 接收的数据包 数据包 /s
-n DEV txpkt/s 传输的数据包 数据包 /s
-n DEV rxkB/s 接收的千字节 千字节 /s
-n DEV txkB/s 传输的千字节 千字节 /s
-n EDEV rxerr/s 接收数据包错误 数据包 /s
-n EDEV txerr/s 传输数据包错误 数据包 /s
-n EDEV coll/s 碰撞 数据包 /s
-n EDEV rxdrop/s 接收数据包丢包(缓冲满) 数据包 /s
-n EDEV txdrop/s 传输数据包丢包(缓冲满) 数据包 /s
-n EDEV rxfifo/s 接收的数据包 FIFO 超限错误 数据包 /s
-n EDEV txfifo/s 传输的数据包 FIFO 超限错误 数据包 /s
-n IP irec/s 输入的数据报文(接收) 数据报文 /s
-n IP fwddgm/s 转发的数据报文 数据报文 /s
-n IP orq/s 输出的数据报文请求(传输) 数据报文 /s
-n EIP idisc/s 输入的丢弃(例如,缓冲满) 数据报文 /s
-n EIP odisc/s 输出的丢弃(例如,缓冲满) 数据报文 /s
-n TCP active/s 新的主动 TCP 连接(connect()) 连接数 /s
-n TCP active/s 新的被动 TCP 连接(listen()) 连接数 /s
-n TCP active/s 输入的段(接收) 段 /s
-n TCP active/s 输出的段(接收) 段 /s
-n ETCP active/s 主动 TCP 失败连接 连接数 /s
-n ETCP active/s TCP 段重传 段 /s
-n SOCK totsck 使用中的总数据包 sockets
-n SOCK ip-frag 当前队列中的 IP 数据片 fragments
-n SOCK tcp-tw TIME-WAIT 中的 TCP 套接字 sockets

TCP 调优(Tune TCP)

我们知道TCP链接是有很多开销的,一个是会占用文件描述符,另一个是会开缓存,一般来说一个系统可以支持的TCP链接数是有限的,我们需要清楚地认识到TCP链接对系统的开销是很大的。正是因为TCP是耗资源的,所以,很多攻击都是让你系统上出现大量的TCP链接,把你的系统资源耗尽。比如著名的SYNC Flood攻击。

所以,我们要注意配置KeepAlive参数,这个参数的意思是定义一个时间,如果链接上没有数据传输,系统会在这个时间发一个包,如果没有收到回应,那么TCP就认为链接断了,然后就会把链接关闭,这样可以回收系统资源开销。(注:HTTP层上也有KeepAlive参数)对于像HTTP这样的短链接,设置一个1-2分钟的keepalive非常重要。这可以在一定程度上防止DoS攻击。有下面几个参数(下面这些参数的值仅供参考):

net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 20
net.ipv4.tcp_fin_timeout = 30

对于TCP的TIME_WAIT这个状态,主动关闭的一方进入TIME_WAIT状态,TIME_WAIT状态将持续2个MSL(Max Segment Lifetime),默认为4分钟,TIME_WAIT状态下的资源不能回收。有大量的TIME_WAIT链接的情况一般是在HTTP服务器上。对此,有两个参数需要注意,

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

前者表示重用TIME_WAIT,后者表示回收TIME_WAIT的资源。

TCP还有一个重要的概念叫RWIN(TCP Receive Window Size),这个东西的意思是,我一个TCP链接在没有向Sender发出ack时可以接收到的最大的数据包。为什么这个很重要?因为如果Sender没有收到Receiver发过来ack,Sender就会停止发送数据并会等一段时间,如果超时,那么就会重传。这就是为什么TCP链接是可靠链接的原因。重传还不是最严重的,如果有丢包发生的话,TCP的带宽使用率会马上受到影响(会盲目减半),再丢包,再减半,然后如果不丢包了,就逐步恢复。相关参数如下:

net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

一般来说,理论上的RWIN应该设置成:吞吐量 * 回路时间。Sender端的buffer应该和RWIN有一样的大小,因为Sender端发送完数据后要等Receiver端确认,如果网络延时很大,buffer过小了,确认的次数就会多,于是性能就不高,对网络的利用率也就不高了。也就是说,对于延迟大的网络,我们需要大的buffer,这样可以少一点ack,多一些数据,对于响应快一点的网络,可以少一些buffer。因为,如果有丢包(没有收到ack),buffer过大可能会有问题,因为这会让TCP重传所有的数据,反而影响网络性能。(当然,网络差的情况下,就别玩什么高性能了) 所以,高性能的网络重要的是要让网络丢包率非常非常地小(基本上是用在LAN里),如果网络基本是可信的,这样用大一点的buffer会有更好的网络传输性能(来来回回太多太影响性能了)。

另外,我们想一想,如果网络质量非常好,基本不丢包,而业务上我们不怕偶尔丢几个包,如果是这样的话,那么,我们为什么不用速度更快的UDP呢?你想过这个问题了吗?

UDP 调优

网卡调优

对于网卡,我们也是可以调优的,这对于千兆以及网网卡非常必要,在Linux下,我们可以用ifconfig查看网上的统计信息,如果我们看到overrun上有数据,我们就可能需要调整一下txqueuelen的尺寸(一般默认为1000),我们可以调大一些,如:ifconfig eth0 txqueuelen 5000。Linux下还有一个命令叫:ethtool可以用于设置网卡的缓冲区大小。在Windows下,我们可以在网卡适配器中的高级选项卡中调整相关的参数(如:Receive Buffers, Transmit Buffer等,不同的网卡有不同的参数)。把Buffer调大对于需要大数据量的网络传输非常有效。

Displays bandwidth rates in bytes/sec:

$ iftop -i <interface> -B

Reference