2

我们在 LAN 上的许多 Linux 服务器上大量使用多播消息传递。我们看到很多延误。我们基本上会发送大量的小包裹。我们更关心延迟而不是吞吐量。这些机器都是现代的多核机器(如果算上超线程,至少有 4 个,通常是 8 个,16 个)机器,负载总是 2.0 或更低,通常负载小于 1.0。网络硬件的容量也低于 50%。

我们看到的延迟看起来像排队延迟:数据包将迅速开始增加延迟,直到看起来它们堵塞,然后恢复正常。

消息传递结构基本上是这样的:在“发送线程”中,从队列中拉出消息,添加时间戳(使用gettimeofday()),然后调用send(). 接收程序接收消息,为接收时间加上时间戳,并将其推送到队列中。在一个单独的线程中,处理队列,分析发送和接收时间戳之间的差异。(请注意,我们的内部队列不是问题的一部分,因为时间戳是在我们的内部队列之外添加的。)

我们真的不知道从哪里开始寻找这个问题的答案。我们不熟悉 Linux 内部结构。我们的怀疑是内核在发送端或接收端(或两者)对数据包进行排队或缓冲。但我们不知道如何追踪和追踪它。

值得一提的是,我们使用的是 CentOS 4.x(RHEL 内核 2.6.9)。

4

3 回答 3

3

这是一个很好的问题。在 CentOS 上,像大多数 *nix 风格一样,每个多播套接字都有一个 UDP 接收/发送缓冲区。此缓冲区的大小由 sysctl.conf 控制,您可以通过调用 /sbin/sysctl -a 查看缓冲区的大小

以下项目显示了我的默认和最大 udp 接收大小(以字节为单位)。这些数字越大,如果您的应用程序消耗数据的速度太慢,网络/内核可能会引入更多的缓冲和延迟。如果您对数据丢失建立了良好的容忍度,则可以使这些缓冲区非常小,并且您将看不到上述延迟的增加和恢复。权衡是缓冲区溢出时的数据丢失——您可能已经看到了。

[~]$ /sbin/sysctl -a | mem net.core.rmem_default = 16777216 net.core.wmem_default = 16777216 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216

在大多数情况下,您需要将 default = 设置为您的最大值,除非您在创建套接字时控制它。

您可以做的最后一件事(取决于您的内核版本)是查看您的进程或至少整个框的 PID 的 UDP 统计信息。

猫/proc/net/snmp | grep -i Udp Udp: InDatagrams NoPorts InErrors OutDatagrams Udp: 81658157063 145 616548928 3896986

cat /proc/PID/net/snmp | grep -i Udp Udp: InDatagrams NoPorts InErrors OutDatagrams Udp: 81658157063 145 616548928 3896986

如果我的帖子不清楚,延迟是由于您的应用程序没有足够快地消耗数据并迫使内核缓冲上述结构中的流量。网络、内核,甚至你的网卡环形缓冲区都可以在延迟中发挥作用,但所有这些项目通常只会增加几毫秒。

让我知道您的想法,我可以为您提供更多信息,让您了解如何在应用中查看以提高性能。

于 2010-02-19T14:38:36.840 回答
1

数据包可以在发送和接收端内核、NIC 和网络基础设施中排队。您会发现大量可以测试和调整的项目。

对于 NIC,您通常可以找到中断合并参数 - NIC 在通知内核或在等待批处理数据包时发送到线路之前将等待多长时间。

对于 Linux,您有发送和接收“缓冲区”,它们越大,您越有可能在批处理操作中处理数据包时遇到更高的延迟。

对于架构和 Linux 版本,您必须了解上下文切换的成本以及是否启用了锁或抢先调度。考虑最小化运行的应用程序的数量,使用进程亲和性将进程锁定到特定的内核。

不要忘记计时,您使用的 Linux 内核版本在gettimeofday()时钟(2-4 毫秒)上的精度非常差,而且调用成本很高。考虑使用替代方案,例如从核心 TSC 或外部 HPET 设备读取。

来自英特尔的图表: 替代文字 http://www.theinquirer.net/IMG/142/96142/latency-580x358.png?1272514422

于 2010-03-19T10:45:15.730 回答
1

如果您决定需要在生产环境中捕获数据包,则可能值得考虑使用交换机上的监控端口并使用非生产机器捕获数据包。这也将允许您在传输路径上的多个点捕获数据包并比较您所看到的。

于 2010-03-19T10:57:47.723 回答