简述linux系统UDP丢包问题分析思路(上)

电子说

1.2w人已加入

描述

最近工作中遇到某个服务器应用程序 UDP 丢包,在排查过程中查阅了很多资料,总结出来这篇文章,供更多人参考。

在开始之前,我们先用一张图解释 linux 系统接收网络报文的过程。

  1. 首先网络报文通过物理网线发送到网卡
  2. 网络驱动程序会把网络中的报文读出来放到 ring buffer 中,这个过程使用 DMA(Direct Memory Access),不需要 CPU 参与
  3. 内核从 ring buffer 中读取报文进行处理,执行 IP 和 TCP/UDP 层的逻辑,最后把报文放到应用程序的 socket buffer 中
  4. 应用程序从 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 相关的报文数据:

[root@holodesk02 GOD]# netstat -s -uIcmpMsg:    InType0: 3    InType3: 1719356    InType8: 13    InType11: 59    OutType0: 13    OutType3: 1737641    OutType8: 10    OutType11: 263Udp:    517488890 packets received    2487375 packets to unknown port received.    47533568 packet receive errors    147264581 packets sent    12851135 receive buffer errors    0 send buffer errorsUdpLite: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 eth0Ring parameters for eth0:Pre-set maximums:RX:        4096RX Mini:    0RX Jumbo:    0TX:        4096Current hardware settings:RX:        256RX Mini:    0RX Jumbo:    0TX:        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/

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分