最近工作中遇到某个服务器应用程序 UDP 丢包,在排查过程中查阅了很多资料,总结出来这篇文章,供更多人参考。
在开始之前,我们先用一张图解释 linux 系统接收网络报文的过程。
- 首先网络报文通过物理网线发送到网卡
- 网络驱动程序会把网络中的报文读出来放到 ring buffer 中,这个过程使用 DMA(Direct Memory Access),不需要 CPU 参与
- 内核从 ring buffer 中读取报文进行处理,执行 IP 和 TCP/UDP 层的逻辑,最后把报文放到应用程序的 socket buffer 中
- 应用程序从 socket buffer 中读取报文进行处理
在接收 UDP 报文的过程中,图中任何一个过程都可能会主动或者被动地把报文丢弃,因此丢包可能发生在网卡和驱动,也可能发生在系统和应用。
之所以没有分析发送数据流程,一是因为发送流程和接收类似,只是方向相反;另外发送流程报文丢失的概率比接收小,只有在应用程序发送的报文速率大于内核和网卡处理速率时才会发生。
本篇文章假定机器只有一个名字为 eth0
的 interface,如果有多个 interface 或者 interface 的名字不是 eth0,请按照实际情况进行分析。
NOTE:文中出现的 RX
(receive) 表示接收报文,TX
(transmit) 表示发送报文。
确认有 UDP 丢包发生
要查看网卡是否有丢包,可以使用 ethtool -S eth0
查看,在输出中查找 bad
或者 drop
对应的字段是否有数据,在正常情况下,这些字段对应的数字应该都是 0。如果看到对应的数字在不断增长,就说明网卡有丢包。
另外一个查看网卡丢包数据的命令是 ifconfig
,它的输出中会有 RX
(receive 接收报文)和 TX
(transmit 发送报文)的统计数据:
ifconfig eth0
...
RX packets 3553389376 bytes 2599862532475 (2.3 TiB)
RX errors 0 dropped 1353 overruns 0 frame 0
TX packets 3479495131 bytes 3205366800850 (2.9 TiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
...
此外,linux 系统也提供了各个网络协议的丢包信息,可以使用 netstat -s
命令查看,加上 --udp
可以只看 UDP 相关的报文数据:
GOD]# netstat -s -u
IcmpMsg:
InType0: 3
InType3: 1719356
InType8: 13
InType11: 59
OutType0: 13
OutType3: 1737641
OutType8: 10
OutType11: 263
Udp:
517488890 packets received
2487375 packets to unknown port received.
47533568 packet receive errors
147264581 packets sent
12851135 receive buffer errors
0 send buffer errors
UdpLite:
IpExt:
OutMcastPkts: 696
InBcastPkts: 2373968
InOctets: 4954097451540
OutOctets: 5538322535160
OutMcastOctets: 79632
InBcastOctets: 934783053
InNoECTPkts: 5584838675
对于上面的输出,关注下面的信息来查看 UDP 丢包的情况:
packet receive errors
不为空,并且在一直增长说明系统有 UDP 丢包packets to unknown port received
表示系统接收到的 UDP 报文所在的目标端口没有应用在监听,一般是服务没有启动导致的,并不会造成严重的问题receive buffer errors
表示因为 UDP 的接收缓存太小导致丢包的数量
NOTE:并不是丢包数量不为零就有问题,对于 UDP 来说,如果有少量的丢包很可能是预期的行为,比如丢包率(丢包数量/接收报文数量)在万分之一甚至更低。
网卡或者驱动丢包
之前讲过,如果 ethtool -S eth0
中有 rx_***_errors
那么很可能是网卡有问题,导致系统丢包,需要联系服务器或者网卡供应商进行处理。
# ethtool -S eth0 | grep rx_ | grep errors
rx_crc_errors: 0
rx_missed_errors: 0
rx_long_length_errors: 0
rx_short_length_errors: 0
rx_align_errors: 0
rx_errors: 0
rx_length_errors: 0
rx_over_errors: 0
rx_frame_errors: 0
rx_fifo_errors: 0
netstat -i
也会提供每个网卡的接发报文以及丢包的情况,正常情况下输出中 error 或者 drop 应该为 0。
如果硬件或者驱动没有问题,一般网卡丢包是因为设置的缓存区(ring buffer)太小,可以使用 ethtool
命令查看和设置网卡的 ring buffer。
ethtool -g
可以查看某个网卡的 ring buffer,比如下面的例子
# ethtool -g eth0
Ring parameters for eth0:
maximums:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings:
RX: 256
RX Mini: 0
RX Jumbo: 0
TX: 256
Pre-set 表示网卡最大的 ring buffer 值,可以使用 ethtool -G eth0 rx 8192
设置它的值。
Linux 系统丢包
linux 系统丢包的原因很多,常见的有:UDP 报文错误、防火墙、UDP buffer size 不足、系统负载过高等,这里对这些丢包原因进行分析。
UDP 报文错误
如果在传输过程中UDP 报文被修改,会导致 checksum 错误,或者长度错误,linux 在接收到 UDP 报文时会对此进行校验,一旦发明错误会把报文丢弃。
如果希望 UDP 报文 checksum 及时有错也要发送给应用程序,可以在通过 socket 参数禁用 UDP checksum 检查:
int disable = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_NO_CHECK, (void*)&disable, sizeof(disable)
原文:https://cizixs.com/2018/01/13/linux-udp-packet-drop-debug/
-
cpu
+关注
关注
68文章
10855浏览量
211610 -
Linux
+关注
关注
87文章
11296浏览量
209361 -
dma
+关注
关注
3文章
561浏览量
100554 -
网络驱动
+关注
关注
0文章
7浏览量
7409
发布评论请先 登录
相关推荐
评论