网络丢包怎么排查(如何解决网络丢包问题)
背景:在使用Linux作为服务器操作系统时,为了达到高并发处理能力,充分利用机器性能,经常会进行一些内核参数的调整优化,但不合理的调整常常也会引起意想不到的其他问题,怎么识别并处理这些问题呢?
本文就一次Linux服务器丢包故障的处理过程,结合Linux内核参数说明和TCP/IP协议栈相关的理论,带大家一起来看看常见的丢包故障定位方法及解决思路。
1.问题现象
本次故障的反馈现象是:从办公网访问公网服务器不稳定,服务器某些端口访问经常超时,但Ping测试显示客户端与服务器的链路始终是稳定低延迟的。
通过在服务器端抓包,我们发现还有两个特点:
从办公网访问服务器有多个客户端,是同一个出口IP,有少部分是始终能够稳定连接的,另一部分间歇访问超时或延迟很高
同一时刻的访问,无论哪个客户端的数据包先到达,服务端会及时处理部分客户端的SYN请求,对另一部分客户端的SYN包“视而不见”
2. 如何排查,怎样解决?
服务器能正常接收到数据包,问题可以限定在两种可能:
- 部分客户端发出的数据包本身异常;
- 服务器处理部分客户端的数触发了某种机制丢弃了数据包。
因为出问题的客户端能够正常访问公网上其他服务,后者的可能性更大。那么,有哪些情况会导致Linux服务器丢弃数据包?
一、防火墙拦截
服务器端口无法连接,通常就是查看防火墙配置了,虽然这里已经确认同一个出口IP的客户端有的能够正常访问,但也不排除配置了DROP特定端口范围的可能性。
如何确认?
查看iptables Filter表,确认是否有相应规则会导致此丢包行为,容易排除防火墙拦截的可能性。
二、连接跟踪表溢出
除了防火墙本身配置DROP规则外,与防火墙有关的还有连接跟踪表nf_conntrack,Linux为每个经过内核网络栈的数据包,生成一个新的连接记录项,当服务器处理的连接过多时,连接跟踪表被打满,服务器会丢弃新建连接的数据包。
如何确认?
通过dmesg可以确认是否有该情况发生:如果输出值中有“nf_conntrack: table full,dropping packet”,说明服务器nf_conntrack表已经被打满。
通过conntrack工具或/proc文件系统查看nf_conntrack表实时状态:在本案例中,当前连接数远没有达到跟踪表最大值,因此排除这个因素。
如何解决?
如果确认服务器因连接跟踪表溢出而开始丢包,首先需要查看具体连接判断是否正遭受DOS攻击,如果是正常的业务流量造成,则可以考虑调整nf_conntrack的参数:
- nf_conntrack_max决定连接跟踪表的大小,默认值是65535,可以根据系统内存大小计算一个合理值:CONNTRACK_MAX = RAMSIZE(in bytes)/16384/(ARCH/32),如32G内存可以设置1048576
- nf_conntrack_buckets决定存储conntrack条目的哈希表大小,默认值是nf_conntrack_max的1/4,延续这种计算方式:BUCKETS = CONNTRACK_MAX/4,如32G内存可以设置262144
- nf_conntrack_tcp_timeout_established决定ESTABLISHED状态连接的超时时间,默认值是5天,可以缩短到1小时,即3600。
三、Ring Buffer溢出
排除了防火墙的因素,我们从底向上来看Linux接收数据包的处理过程,首先是网卡驱动层。
如下图所示,物理介质上的数据帧到达后首先由NIC(网络适配器)读取,写入设备内部缓冲区Ring Buffer中,再由中断处理程序触发Softirq从中消费,Ring Buffer的大小因网卡设备而异。
当网络数据包到达(生产)的速率快于内核处理(消费)的速率时,Ring Buffer很快会被填满,新来的数据包将被丢弃。
如何确认?
通过ethtool -S指令或查看/proc/net/dev可以得到因Ring Buffer满而丢弃的包统计,在统计项中以fifo标识:本案例中服务器的接收方向的fifo丢包数并没有增加,自然也排除这个原因。
如何解决?
如果发现服务器上某个网卡的fifo数持续增大,可以去确认CPU中断是否分配均匀,也可以尝试增加Ring Buffer的大小,通过ethtool -g可以查看网卡设备Ring Buffer最大值,ethtool -G修改Ring Buffer当前设置。
四、netdev_max_backlog溢出
netdev_max_backlog是内核从NIC收到包后,交由协议栈(如IP、TCP)处理之前的缓冲队列。每个CPU核都有一个backlog队列,与Ring Buffer同理,当接收包的速率大于内核协议栈处理的速率时,CPU的backlog队列不断增长,当达到设定的netdev_max_backlog值时,数据包将被丢弃。
如何确认?
通过查看/proc/net/softnet_stat可以确定是否发生了netdev backlog队列溢出。其中:
- 每一行代表每个CPU核的状态统计,从CPU0依次往下
- 每一列代表一个CPU核的各项统计:第一列代表中断处理程序收到的包总数;第二列即代表由于netdev_max_backlog队列溢出而被丢弃的包总数
在本案例的服务器统计中,并没有因为netdev_max_backlog导致的丢包。
如何解决?
netdev_max_backlog的默认值是1000,在高速链路上,可能会出现上述第二列统计不为0的情况,可以适当调大内核参数
net.core.netdev_max_backlog到2000来解决。
感谢大家的收藏与转发,记得要点击关注哟,您的关注,是我们更新的动力!