首页 > 解决方案 > 我可以使用 SO_REUSEPORT 将单个 UDP 流分发到多个接收器线程吗?

问题描述

我的 Linux 应用程序需要以每秒约 600,000 个数据包的速度接收单个 UDP 流,其中包含中等大小的数据包(约 1 KB)。我目前的实现很幼稚:它有一个简单地重复调用的单个线程recv(),将接收到的数据放入队列中以由另一个线程处理。因此,接收线程只负责拉入数据包。

在我完成的一些初始测试中,在线程完全利用其 CPU 内核之前,我每秒只能接收 200,000-300,000 个数据包。这显然不足以满足每秒约 600,000 个数据包的目标。

理想情况下,我会找到某种方法在多个线程之间分配数据包接收负载。在寻找问题的解决方案时,我遇到了SO_REUSEPORTsocket option,它允许多个 TCP/UDP 线程绑定到同一个 IP/端口组合。起初,这似乎正是我想要的。

不过,文章也指出了这个细节:

传入的连接和数据报使用基于连接的 4 元组的散列分配到服务器套接字,即对等 IP 地址和端口加上本地 IP 地址和端口。这意味着,例如,如果客户端使用同一个套接字将一系列数据报发送到服务器端口,那么这些数据报将全部定向到同一个接收服务器(只要它继续存在)。这简化了在客户端和服务器之间进行有状态对话的任务。

因此,如果我只有一个 UDP 流,上面的散列实现将产生所有被定向到同一接收器线程的数据包,从而阻碍我并行化工作的尝试。因此,问题是:有没有办法使用或其他机制从多个线程接收单个 UDP 数据包流?SO_REUSEPORT

请注意,我的应用程序可以处理数据包的重新排序;数据报格式化的协议包含排序信息,我可以使用这些信息在之后正确地重新排序它们。

标签: linuxsocketsudp

解决方案


如果您在过去 3 年没有找到解决方案,请查看SO_ATTACH_REUSEPORT_CBPF. 我们遇到了完全相同的问题,我们通过附加简单的 BPF 程序解决了这个问题,该程序随机分布数据报 mod n。


推荐阅读