接收大量(r)卷的UDP通信时,CPU负载过高(Windows)

我正在研究使用大量传入数据进行进一步处理的应用程序(组播传输stream,具体而言)的问题。

情况如下:添加多个组播stream。 每个都有它自己的接收线程从套接字接收数据,然后将其复制到环缓冲区。 它不再做了。

在大约500至600兆位,一个特定的CPU核心达到100%。 实际上,在初始化stream时,随着以太网stream量的增加,我可以看到它几乎线性地爬向负载。

套接字代码使用WSA重叠的API。 即使当我减less线程来做到这一点(即不复制到环缓冲区,这反过来将主应用程序的任何负载减less到接近于零),我都可以很容易地将这个特定的内核陷入红色。 另外有趣的是,即使我通过关联设置将其限制在4个完全不同的核心上,该负载也存在于该特定核心上。 我最后得出的结论是在操作系统或驱动程序级别上花费了一些时间。

我已经尝试在拷贝之前一次收集n个数据报(即超过1500字节的MTU),但这只会让事情变得更糟。 我也检查了我的套接字configuration正确(非阻塞,返回值都可以)。

我想知道是否有人可以告诉我有关这个问题,也许有这个问题或有一些有用的见解,如何在Windows上有效地处理这些stream量。

(我正在使用的NIC:Intel PRO PT1000)

UPDATE

我只设置了一个testing应用程序,只有一个目标:从任意数量的多播中获取传入的UDP。 我正在用Lenbuild议的IO完成端口策略来做这件事。 现在我可以很容易地从28个组播中获得1Gbit的CPU负载(毕竟现在我没有对数据包做任何处理),但是当使用更多(更小带宽)的组播时,一般在70以上,变得越来越糟糕,工作线程似乎不平衡,大多在浪费时间(等待)。

NIC中断负载现在不是限制因素(之前是这样)。

我对这个multithreadingnetworking资料很陌生。 工作线程只不过是在IO完成端口(GetQueuedCompletionStatusEx())/ INFINITE上等待,然后当stream读取完成时,我立即发出另一个循环(如果我可以在同一个stream上同时获得更多,我将采取那些没有发出新的IO事件,FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)。

我拥有和CPU核心一样多的工作线程(任何事情都让事情变得更糟)。

没想到这个提出了一个新的问题 – 但是,再次,任何帮助非常感谢!

这是我的testing应用程序的来源。 (C ++) – 应该可读:-) http://pastebin.com/xWEPPbi6

  1. 用SysInternals Process Explorer工具查看你的系统,看看这个CPU正在被使用的地方,它可能被分配给“中断”,在这种情况下,它是处理NIC中断的CPU。 如果是这种情况,请查看您的网卡驱动程序,并查看是否可以启用或调整中断合并,以便NIC为相同数量的数据报生成更少的中断。

  2. 查看是否可以卸载数据报校验和计算,如果它尚未卸载到网卡,那么计算机上的CPU时间将被使用。 请注意,如果网卡无法跟上并且驱动程序不曾抛出任何数据报,那么非分页池使用可能会存在潜在的问题(请参阅此博客 )。

  3. 切换到使用GetQueuedCompletionStatusEx(),你说你正在使用“WSA重叠API”希望你的意思是I / O完成端口方法。 如果是的话,那么GetQueuedCompletionStatusEx()将允许你用较少的系统调用来读取更多的数据报。

  4. 切换到使用RIO API(请参阅此处了解Windows注册I / O网络扩展的介绍 )。 这继续了3的主题,并提供了更多的性能获取数据报到您的代码。

已更新以反映问题更新:

  1. 发出多个读取开始以获得良好的挂起读取积压。 所以,例如,有100个待处理的读取,然后开始发布新的(如果您使用“跳过完成端口”处理,但更复杂一点,但想法是建立积压。

  2. 从GQCSEx中检索多个完成,或者没有意义使用它。

  3. 当你“内联”完成时避免递归,更喜欢循环。 否则,你正在咀嚼。

有几件事要检查高UDP多播接收率。

  1. 通过检查网络控制面板NIC属性或PowerShell的get-NetAdapterAdvancedProperties来查看您的NIC是否支持RSS(接收端扩展)。 如果不是,则获取一个可以进行配置的网卡,并配置一些RSS队列,其中数量大于1,<=物理核心数量(非超线程核心数量)。 这将在多个核心之间分配内核中的网络处理。 你写了一个核心是固定的 – 如果它在DPC时间固定,(检查perfmon ProcessorInformation DPC时间%,那么你需要使用RSS。
  2. 确保已启用NIC提供的最大接收描述符数。 高速组播的默认值太低。
  3. 确保您的接收套接字缓冲区大小足够大。 如果不是的话,你会因为缓冲不足而在重负载下丢失数据报。 根据接收音量和您的程序处理能力,可能需要10 MB的MB。
  4. 如果您正在运行WS2012或WIn8,请查看新的性能计数器,Microsoft BSP / Datagrams Dropped&Datagrams每秒丢弃。 如果这些在重负载下增加,则需要更多的套接字缓冲,或者程序需要运行得更快。 无论哪种方式,你正在放弃接收流量。
  5. 如果您正在使用线程池(无论是您自己的还是O / S提供的),请注意这可以重新排序到达(对于金融市场数据不利),您必须构建程序和线程模型以避免这种情况。
  6. 使用GetQueuedCompletionStatusEx实际上对这种应用程序没有什么帮助。 如果你想在一次快速通话中获得多个完成,这就是RIO设计的目的。

这个信息应该允许你处理大量的多播流量。 我们有许多客户可以毫无困难地使用常规套接字和Windows server 2008 R2及更高版本这样的安排,全天获得完整的市场数据。 Windows server 2012可以更快速地处理多播流量,并且如果将RIO更快地添加到您的程序中。 如果你正在运行非常旧的服务器版本(例如Windows server 2003),那么你将无法获得良好的性能。 其中一部分与底层硬件平台的发展有关,这些平台不包括诸如消息信号中断之类的东西,这使得我们能够使用RSS获得较大的多播接收比例增益。

我希望这有帮助。

埃德布里格斯微软公司