UDP数据丢包跟踪与总结

参考文章链接1:https://www.cnblogs.com/h2zZhou/p/12015409.html(侵权必删)

丢包检查方法

  • 给每个UDP包编号,对比收发端的接收到的包。对于UDP协议层上的包,例如RTP包,可以从RTP包中读出包的序列号进行判断。
  • 抓包。发送端和接收端分别抓包。linux下可以使用tcpdump,windows下使用wireshark。
  • linux下,可以使用watch netstat -su查看丢包统计。主要看RcvbufErrors和SndbufErrors。如果两个统计项的数字都在不断增加,表明网卡有丢包。

发送方丢包

发送的包太大

发送的包比64K大会导致UDP协议sendto返回错误。
发送的包比MTU大,UDP包在接收端容易丢包,可查看接收端的网卡统计。可考虑把包切分到MTU一下再发送。

发包速度太快

发包速度太快的话,可能有两个问题:1.接收端来不及接收导致接收端丢包。2.发送端网卡处理不过来。这个时候sendto没有返回错误,但是用netstat查看会发现SndbufErrors不断上升,有可能是网卡的输出队列太小导致。可以考虑使用ifconfig命令把txqueuelen设置大一些。

UDP包流量太大

同一个端口发送的数据量太大时会导致网卡丢包,这个时候可以用netstat查看会发现SndbufErrors不断上升。sendto会返回-1.这个时候可以考虑增大/proc/sys/net/core/wmem_max的值。
这种情况尤其是同时给多个客户端发送音视频数据时导致。笔者曾经遇到过这么一次情况。一个端口向8个客户端发送视频流时,网卡流量大概400M/s,sendto会返回-1,errno 11.程序里也调用setsockopt设置了发送缓冲区为60M,然而还是会丢包。后来将系统参数/proc/sys/net/core/wmem_max设到60M才解决问题。

接收端丢包

接收缓冲区太小

接收缓冲区小于发送客户端的包的大小,或者接收客户端recvfrom速度太慢,导致接收缓冲区满丢弃数据。前一种问题,可以考虑增大接收缓冲区。后一种问题,可以考虑将接收操作和业务处理操作分离到不同的线程来处理

 

参考文章链接2:https://www.cnblogs.com/lsgxeva/p/11124762.html(侵权必删)

解决方案:通过开启网卡多队列以及中断绑定来解决大流量下的网络丢包问题(暂时未测试)

1、判断当前系统环境是否支持多队列网卡,执行命令:

lspci -vvv

如果在Ethernet项中。含有MSI-X: Enable+ Count=9 Masked-语句,则说明当前系统环境是支持多队列网卡的,否则不支持。

2、ethtool -l eth0命令可以看到eth0网卡是否支持多队列,最多支持多少、当前开启多少

3、设置网卡当前使用多队列。运行命令:ethtool -L eth0 combined N为要使能的队列数

4、要确保多队列确实生效,可以查看文件:

# ls /sys/class/net/eth0/queues/

rx-0 rx-2 rx-4 rx-6 tx-0 tx-2 tx-4 tx-6
rx-1 rx-3 rx-5 rx-7 tx-1 tx-3 tx-5 tx-7

如上,如果rx数量是设定值,则正确。

X86系统采用中断机制协同处理CPU与其他设备工作。长久以来网卡的中断默认由cpu0处理,在大量小包的网络环境下可能出现cpu0负载高,而其他cpu空闲。后来出现网卡多队列技术解决这个问题。

通过命令cat /proc/interrupts 查看系统中断信息,应该是长下面这个样子。第一列是中断号,后面是每个cpu的中断数,可以通过grep过滤网卡来看相关的中断再那个CPU上执行

5、中断绑定

我们可以绑定中断号与处理CPU之间的关系,Linux系统用irqbalance服务优化中断分配,它能自动收集数据,调度中断请求。为了了解中断绑定,我们把irqbalance服务关掉,手工调整绑定关系。

/proc/irq/{IRQ_ID}/smp_affinity,中断IRQ_ID的CPU亲和配置文件,16进制
/proc/irq/{IRQ ID}/smp_affinity_list,10进制,与smp_affinity相通,修改一个相应改变。

[root@localhost ~]# cat /proc/interrupts  | grep eth0

               CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7

143:          0          0          0          0          1          0          0          0  IR-PCI-MSI-edge      eth0
 144:         68         67         58  297886391         69         57         68         59  IR-PCI-MSI-edge      eth0-TxRx-0
 145:  282217533         59         54         55         62         61         56         57  IR-PCI-MSI-edge      eth0-TxRx-1
 146:         52  269243896         51         46         55         50         53         54  IR-PCI-MSI-edge      eth0-TxRx-2
 147:         44         10         14         11         35  292342171         12          7  IR-PCI-MSI-edge      eth0-TxRx-3

[root@localhost ~]# cat /proc/irq/144/smp_affinity

08
[root@localhost ~]# cat /proc/irq/144/smp_affinity_list 
3

#上面表示的是08【00001000】,表示在cpu3上(从右往左,依次从CPU0~CPU7),和下面的3保持一致

[root@localhost ~]# echo 4 > /proc/irq/144/smp_affinity

修订后在进行压力测试,观察eth0的中断分压

RPS/RFS

RSS需要硬件支持,在不支持RSS的环境中,RPS/RFS提供了软件的解决方案。RPS(Receive Packet Steering)是把一个rx队列的软中断分发到多个CPU核上,从而达到负载均衡的目的。RFS(Receive Flow Steering)是RPS的扩展,RPS只依靠hash来控制数据包,提供负载平衡,但是没有考虑到应用程序的位置(指应用程序所在CPU)。RFS目标是通过指派应用线程正在运行的CPU处理中断,增加数据缓存的命中率。

参考文章链接3:https://cloud.tencent.com/developer/article/1638140

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

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

UDP数据丢包跟踪与总结_第1张图片

 

 

你可能感兴趣的:(网络通信)