我在Linux上编写了一个UDP C ++服务器应用程序,现在正在加载测试它以查看它可以处理多少个客户端。我发现它大约有150个同时发送数据包的客户端以每秒2-4个的速率发送数据包。
之后添加的客户端将导致其他客户端的数据包被丢弃。
服务器本身没有压力,使用的CPU和内存不到10%。网络也没有受到压力,大约15K字节/秒。数据包以大约200个数据包/秒的速度到达服务器(使用一个UDP套接字进行读写)。服务器线程本身仍然在此负载级别短时间内休眠。
问题:
关于什么是瓶颈的任何想法? CPU,网络和服务器代码本身似乎都没有受到重视。操作系统是否无法处理这个UDP数据包?
硬件功耗非常低 - 1.5 MHz时的单核Pentium等效功能。 NIC为100M位/秒。我正在运行Ubuntu 11.1。
本文可能相关:Upper limit to UDP performance on windows server 2008
更新: 服务器设置UDP套接字,然后创建3个线程和2个队列。套接字读取时的第一个线程阻塞,如下所示:
while (1)
{
recvfrom(this->socket, readBuf, BUFSIZE, 0, (sockaddr *)&address, &addressLen);
pushBack(this->inputQueue, message);
}
第二个线程在inputQueue上休眠。当条件被发出信号并处理消息时,它会唤醒。它将处理过的消息发送到outputQueue:
while (1)
{
sleepOnQ(this->inputQueue);
popFront(this->inputQueue);
processMessage();
pushBack(this->outputQueue, message);
}
第三个线程在outputQueue上休眠,并将消息从UDP套接字发送到目标。注意,它与用于阅读的插座相同。
while (1)
{
sleepOnQ(this->outputQueue);
popFront(this->outputQueue);
processMessage();
sendto(this->socket, message, ... );
}
每个客户端和消息的处理量很小。正如我所提到的,当服务器处理200条消息/秒时,它使用了大约10%的真正笨拙的CPU。
以下是系统中的一些内核参数:
net.core.wmem_max = 114688
net.core.rmem_max = 114688
net.core.wmem_default = 114688
net.core.rmem_default = 114688
有关数据同步的更多信息
到目前为止,答案让我想到了两件事:
记录可能是一个问题,我会尝试将其关闭并报告结果。但是,可能更重要的是线程之间队列的争用。由于CPU很低,因此线程可能会花费大量时间等待访问队列。
在这个服务器的第一次迭代中,我试图锁定数据很棘手。服务器非常快,但在达到800包/秒时崩溃了。当前版本锁定整个队列。也许我需要一种更好的方法来同步线程。
回答问题
我在这里获得的信息非常有用。问题是测试客户端出现了骨头错误,但进行调查有助于消除此处建议的原因。
仅供参考我的结果。一旦我解决了客户端的问题,服务器接受了大约800个数据包/秒,CPU利用率为70%。我已经将OS读/写缓冲区从128K增加到12MB。我没有测试读取缓冲区是否已填满。我怀疑操作系统读取缓冲区是一个问题,因为在最高速度下,服务器读取线程在每次读取10次或20次时都会在读取时阻塞。
800包/秒仍然太慢,所以我从服务器上删除了日志。这产生了巨大的变化。服务器能够以70%的cpu util从1400多个客户端接收2900条消息/秒。
我还测试了读取线程是否在等待锁定。即使在最高速度下,我发现它也不必等待超过1毫秒,因此它不是2900消息/秒的因素。也许它会在更快的CPU上运行。
此时服务器受CPU限制,并找到我需要更强大的CPU上的下一个瓶颈。 谢谢你的帮助!
答案 0 :(得分:1)
丢失的最可能原因是UDP套接字的传入数据包缓冲区在第一个线程清空之前填满;在缓冲区已满时接收的任何传入UDP数据包都将被丢弃。
第一个线程无法足够快地清空缓冲区以防止其填满的最可能的原因是,其他东西将其从CPU中移除太长时间......因为它听起来像是在运行一个单核CPU,很可能就是这种情况。您可能希望尝试将第二个和第三个线程设置为较低的优先级(以便第一个线程在出现争用时将在CPU上获得第一个dib)并查看是否有帮助。如果仍然不够好,您可以将进程设置为SCHED_RR'实时'优先级,以确保操作系统中运行的任何其他进程不会使您的第一个线程远离CPU。 (当然,你仍然可以以较低的优先级运行其他线程,因为它们在执行时确实无关紧要。)
答案 1 :(得分:1)
如果传入的UDP数据报不适合UDP输入缓冲区(通常缓冲区已满),则内核将丢弃它。
如果当数据包速率仅为200 / s且CPU负载较低时缓冲区已满,那么您的程序会浪费时间等待其他事情(睡眠结束,某些资源等)而不是新数据包。
仔细检查您的代码。并试图摆脱所有sleep
,nanosleep
和类似的睡眠功能。
如果您将大量(调试)输出打印到串行控制台,它可能会开始阻止您的程序,因为串行端口不是那么快。尽量消除这种瓶颈。