一直以来对Linux网络这块都感觉比较乱
遇到一个UDP丢包的问题:在测试中,一台VM虚拟机,CPU利用率55%左右,内存利用率7%左右,网卡流量也远没到限制的时候出现了丢包情况
使用netstat -su|grep "packet receive errors"|awk '{print $1}' ,每30s查看一次,计算这次和上次之间的数值差值发现存在UDP丢包现象。
首先要看问题出现在哪儿,网络流量的路径是怎样的?
1、网络流量通过有线/无线发送到网卡
2、网卡驱动读取报文放到ring buffer(此时调用DMA,不经过CPU)
3、内核从ring buffer中读取报文进行处理,执行IP层,TCP/UDP层逻辑
4、把报文发到用户态的socket buffer中,应用程序读取socket buffer并进行处理
可能出现问题的阶段:1、网卡处理时丢包 2、内核处理时丢包 3、应用程序处理时
1、网卡阶段:
两种方法:1. ifconfig 查看RX errors dropped
2. ethtool -S eth0 |egrep "err|drop"
如果存在丢包,可以查看网卡的ring buffer size是否设置太小达到瓶颈,使用ethtool -g eth0查看最大值和当前值,使用ethtool -G eth0 rx 1024 进行修改
如果网卡方面没问题,那么尝试内核方面查看
2、内核阶段
linux 系统在接收报文之后,会把报文保存到缓存区中。因为缓存区的大小是有限的,如果出现 UDP 报文过大(超过缓存区大小或者 MTU 大小)、接收到报文的速率太快,都可能导致 linux 因为缓存满而直接丢包的情况。
使用sysctl -a |grep net.core 查看相关参数设置
重点看这几个参数:
/proc/sys/net/core/rmem_max:允许设置的 receive buffer 最大值
/proc/sys/net/core/rmem_default:默认使用的 receive buffer 值
/proc/sys/net/core/wmem_max:允许设置的 send buffer 最大值
/proc/sys/net/core/wmem_dafault:默认使用的 send buffer 最大值
但是这些初始值并不是为了应对大流量的 UDP 报文,如果应用程序接收和发送 UDP 报文非常多,把这个值调大。
如果发现某些参数设置不合理需要修改的话:
方法一:使用 sysctl 命令让它立即生效
接收最大值设置 sysctl -w net.core.rmem_max=56214400 # 设置为 50M
接收默认值设置 sysctl -w net.core.rmem_default=26214400 # 设置为 25M
发送最大值 sysctl -w net.core.wmem_max=26214400 # 设置为 25M
发送默认值 sysctl -w net.core.wmem_default=26214400 # 设置为 25M
方法二:修改对应路径文件的参数或者修改 /etc/sysctl.conf 中对应的参数在下次启动时让参数保持生效(sysctl -p 生效)
3、应用阶段
系统的 UDP buffer size,调节的 sysctl 参数只是系统允许的最大值,每个应用程序在创建 socket 时需要设置自己 socket buffer size 的值。linux 系统会把接受到的报文放到 socket 的 buffer 中,应用程序从 buffer 中不断地读取报文。
另外一个因素是应用读取 buffer 中报文的速度,对于应用程序来说,处理报文应该采取异步的方式。
其他可能原因:
防火墙systemctl status firewalld,或者依赖iptables阻断了部分流量?
要处理的实际业务中,每一个连接会占用一个句柄,测试有反馈有"Too many open files"的错误。这可能导致数据丢失而没有正确执行实际业务。
陆续学习和更新
参考链接(如有侵权请联系删除):https://blog.csdn.net/weixin_40754332/article/details/106924810
此外补充下小工具的使用
netstat 主要是用于列出系统上所有的网络套接字连接情况,包括 tcp, udp 以及 unix 套接字,另外它还能列出处于监听状态(即等待接入请求)的套接字。
-a 显示所有连接
-t TCP连接
-u UDP连接
-l 列出所有处于监听状态的 Sockets
-s 显示所有端口的统计信息,可配合-u/-t使用
Recv-Q表示收到的数据已经在本地接收缓冲,但是还有多少没有被进程取走
send-Q表示本地待发送的数据
这两个值通常应该为0,如果不为0可能是有问题的。packets在两个队列里都不应该有堆积状态。可接受短暂的非0情况。
参考链接:https://blog.csdn.net/wangquan1992/article/details/109508822
ethtool
ethtool eth0 显示网卡状态等信息