Linux UDP数据包丢失的原因

Mat*_*att 13 c c++ linux networking udp

我有一个Linux C++应用程序,它接收有序的UDP数据包.由于排序,我可以很容易地确定数据包丢失或重新排序的时间,即遇到"间隙"时.该系统具有处理间隙的恢复机制,但是,最好首先避免间隙.使用一个简单的基于libpcap的数据包嗅探器,我已经确定硬件级别的数据没有间隙.但是,我发现我的应用程序存在很多差距.这表明内核正在丢弃数据包; 通过查看/ proc/net/snmp文件来确认.当我的应用程序遇到间隙时,Udp InErrors计数器会增加.

在系统级别,我们增加了最大接收缓冲区:

# sysctl net.core.rmem_max
net.core.rmem_max = 33554432
Run Code Online (Sandbox Code Playgroud)

在应用程序级别,我们增加了接收缓冲区大小:

int sockbufsize = 33554432
int ret = setsockopt(my_socket_fd, SOL_SOCKET, SO_RCVBUF,
        (char *)&sockbufsize,  (int)sizeof(sockbufsize));
// check return code
sockbufsize = 0;
ret = getsockopt(my_socket_fd, SOL_SOCKET, SO_RCVBUF, 
        (char*)&sockbufsize, &size);
// print sockbufsize
Run Code Online (Sandbox Code Playgroud)

在调用getsockopt()之后,打印值总是它设置的2倍(上例中的67108864),但我相信这是可以预期的.

我知道无法快速消耗数据会导致数据包丢失.但是,所有这个应用程序都检查顺序,然后将数据推入队列; 实际处理在另一个线程中完成.此外,该机器是现代的(双Xeon X5560,8 GB RAM)和非常轻载.我们确实有几十个相同的应用程序以更高的速率接收数据,但没有遇到这个问题.

除了消耗太慢的应用程序之外,还有其他原因导致Linux内核可能丢弃UDP数据包吗?

FWIW,这是在CentOS 4上,内核为2.6.9-89.0.25.ELlargesmp.

Ste*_*e-o 7

如果你有比核心更多的线程和它们之间相同的线程优先级,那么很可能接收线程缺乏时间来刷新传入的缓冲区.考虑以比其他线程更高的优先级运行该线程.

类似地,虽然通常效率较低的是将线程绑定到一个核心,这样您就不会在核心和相关的缓存刷新之间进行切换.


rac*_*cic 5

我的程序也有类似的问题。它的任务是在一个线程中接收udp数据包,并使用阻塞队列,用另一个线程将它们写入数据库。

我注意到(使用vmstat 1),当系统经历大量 I/O 等待操作(读取)时,我的应用程序没有收到数据包,但系统正在接收它们。

问题是 - 当发生大量 I/O 等待时,写入数据库的线程在持有队列互斥体时会出现 I/O 匮乏。这样,udp 缓冲区就会被传入数据包溢出,因为接收数据包的主线程挂在pthred_mutex_lock().

我通过使用ionice我的进程和数据库进程的 ioniceness (命令)解决了这个问题。将 I/O 计划类别更改为“尽力而为”会有所帮助。令人惊讶的是,即使使用默认的 I/O 性能,我现在也无法重现这个问题。我的内核是2.6.32-71.el6.x86_64。

我仍在开发这个应用程序,因此一旦我了解更多信息,我将尝试更新我的帖子。