如何监控Linux UDP缓冲区可用空间?

Yon*_*oit 47 linux networking udp

我在linux上有一个java应用程序,它打开UDP套接字并等待消息.

在重负载下经过几个小时后,会丢失数据包,即数据包是由内核接收的,而不是我的应用程序接收的(我们在嗅探器中看到丢失的数据包,我们看到netstat中的UDP数据包丢失,我们看不到这些数据包在我们的app日志中).

我们尝试扩大套接字缓冲区,但这没有任何帮助 - 我们之前开始丢失数据包,但就是这样.

对于调试,我想知道在任何给定时刻OS udp缓冲区的完整性.谷歌搜索,但没有找到任何东西.你能帮助我吗?

PS伙计们,我知道UDP是不可靠的.但是 - 我的计算机接收所有UDP消息,而我的应用程序无法使用其中一些消息.我想优化我的应用程序,这就是问题的原因.谢谢.

Ric*_*ckS 61

UDP是一种非常可行的协议.对于正确的工作,这是正确的工具的旧案例!

如果你有一个程序等待UDP数据报,然后在返回等待另一个之前去处理它们,那么你经过的处理时间总是要比数据报的最坏情况到达速度快.如果不是,那么UDP套接字接收队列将开始填充.

短暂的爆发可以容忍这种情况.队列完全按照预期的方式执行 - 在您准备好之前排队数据报.但如果平均到达率经常导致队列积压,那么是时候重新设计你的程序了.这里有两个主要选择:通过狡猾的编程技术减少处理时间,和/或多线程程序.也可以使用跨程序的多个实例的负载平衡.

如上所述,在Linux上,您可以检查proc文件系统以获取有关UDP的最新状态.例如,如果我cat/proc/net/udp节点,我得到这样的东西:

$ cat /proc/net/udp   
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops             
  40: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000     0        0 3466 2 ffff88013abc8340 0           
  67: 00000000:231D 00000000:0000 07 00000000:0001E4C8 00:00000000 00000000  1006        0 16940862 2 ffff88013abc9040 2237    
 122: 00000000:30D4 00000000:0000 07 00000000:00000000 00:00000000 00000000  1006        0 912865 2 ffff88013abc8d00 0         
Run Code Online (Sandbox Code Playgroud)

从这里,我可以看到用户ID 1006拥有的套接字正在侦听端口0x231D(8989),并且接收队列大约是128KB.因为128KB是我系统上的最大大小,这告诉我我的程序在跟上到达的数据报时非常弱.到目前为止已经有2237次丢弃,这意味着UDP层无法将更多数据报放入套接字队列,并且必须删除它们.

您可以随着时间的推移观察您的程序的行为,例如使用:

watch -d 'cat /proc/net/udp|grep 00000000:231D'
Run Code Online (Sandbox Code Playgroud)

另请注意,netstat命令的作用大致相同: netstat -c --udp -an

我的weenie程序的解决方案将是多线程的.

干杯!

  • @Chinaxing`cat/proc/sys/net/core/rmem_max` (5认同)

Jul*_*ano 40

Linux提供了文件/proc/net/udp/proc/net/udp6,其中列出所有打开的UDP套接字(IPv4和IPv6,分别).在它们中,列tx_queuerx_queue以字节显示传出和传入队列.

如果一切按预期工作,您通常不会在这两列中看到任何不同于零的值:一旦您的应用程序生成数据包,它们就会通过网络发送,并且一旦这些数据包从网络到达,您的应用程序就会唤醒并接收它们(recv电话立即返回).rx_queue如果您的应用程序已打开套接字但未调用recv接收数据,或者它没有足够快地处理此类数据,您可能会看到上升.

  • 感谢rx_queue,其余的 - 请参阅更新) (3认同)
  • 海报想知道监视 UDP 统计信息,而不是关于使用哪种协议的意见。通过首先确定层丢失发生的位置,然后可以进行修复。 (2认同)

Ann*_*nne 5

rx_queue 会告诉您任何给定时刻的队列长度,但它不会告诉您队列有多满,即高水位线。无法持续监控该值,也无法以编程方式获取它(请参阅如何获取 UDP 套接字的排队数据量?)。

我可以想象监控队列长度的唯一方法是将队列移动到您自己的程序中。换句话说,启动两个线程——一个以最快的速度读取套接字并将数据报转储到队列中;另一个以最快的速度读取套接字并将数据报转储到队列中。另一个是您的程序从该队列中拉出并处理数据包。当然,这是假设您可以确保每个线程都位于单独的 CPU 上。现在,您可以监控自己队列的长度并跟踪最高水位线。