UDP服务器 - 异步调用是否值得额外的复杂性?

时间:2011-04-20 16:15:44

标签: c# multithreading asynchronous udp scalability

我正在编写需要处理大量客户端的UDP服务器。

协议非常简单 - 单个UDP数据包到达并被解码。它可能需要一个小的确认包。结果通常存储在数据库中。

目前我正在使用单线程UDP服务器设计。它等待具有阻塞接收调用的数据,对数据执行一些相当快速的处理,然后将其粘贴到队列中,以便缓慢的DB内容可以由后台中的另一个进程完成。

我可以使用异步UDP调用(BeginReceieve,EndReceive),但我想知道我会在性能方面获得什么?

很多人说“如果你想要可扩展性,你需要使用异步调用”。它似乎得到了智慧。我之前使用过扭曲,所以我不怕异步设计。

我可以看到为什么使用TCP,或者甚至使用一些更复杂的UDP协议,async是好的。它有助于避免TCP服务器中每个连接一个线程。但我的协议并不需要等待,除非因为没有数据到达而无所事事。

据我了解,如果不需要阻塞,异步调用将同步完成,或者将从线程池启动后台线程,等待数据并在某些存在时调用您的回调,或者在发送完成时,或者当你正在做的任何操作完成时。

我想我可能会“意外地”获得一点点因为当需要阻塞接收时,所产生的相当快的解码将在工作线程而不是主线程中完成。然而,据我所知,只有当没有太多数据要处理时,即只有当这样的最小增益最不实用时,接收才会阻塞。此外,如果值得的话,可以在没有异步的情况下实现相同的增益。

所以,我的主要线程是做4件事之一 - 阻止等待数据,接收数据,处理数据或发送数据。我认为async可能从主线程中删除的唯一其他位是实际接收或发送数据包所花费的时间,但我不知道这些完成的速度有多快 - 例如,如果UDP发送由驱动程序排队,或者如果阻塞呼叫实际上等待直到数据在线路上。

任何人都可以告诉我,我是否真的从这里使用异步调用获益,如果有的话,你能解释一下为什么吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

因为您使用UDP,所以您的发送永远不会阻塞,并且您不需要复用多个套接字(或者如果您这样做,只需要很少的数量)。

所以只做一切的单个线程可能会没问题。

我个人认为使用一些奇特的异步框架作为过早的优化。如果您的服务器范围没有改变(例如,它需要将其他请求发送到其他服务器),那将非常容易。


当您将内容保存到数据库中时,数据库可能会任意慢(即使单个行插入也可能需要很长时间,如果数据库忙)。绝对不应该与网络同步插入数据库,除非你有一些耐久性保证。

是否有少量数据库插入丢失了?您可以将它们排入内存(如果服务器出现故障,则会丢失)。您可以将它们排在光盘上并同步文件(但这可能需要一个合适的IO控制器),然后同步发送响应。

异步数据库API通常不存在(我不知道你是否有),所以如果你的线程在数据库写入时被阻止,它就会阻止整个任务。但是,如果您有足够的耐久性保证,那么您就无法做其他事情。

如果您的规范说“当接收方收到确认数据肯定会被持久存储”时,您必须同步执行数据库操作。

答案 1 :(得分:0)

这都与数字有关。你说网络线程做了一些小的预处理,然后将消息处理委托给后台线程,其中所有数据库的东西都占据了一席之地。在大多数情况下,如果使用UDP,此模型应该足够了,因为此协议在发送消息时并不意味着大量阻塞。

但同样,这完全取决于数字。您在消息预处理上花费了多少百分比的CPU时间(0.5%或15%)?你需要多长时间发送UDP数据包?操作系统将阻止您,直到底层缓冲区有足够的空间供您发送消息。在大多数情况下,这不是问题,但您可能有某些特定情况。

我建议你做一些简单的负载测试来收集数字并做出决定。 AFAIU您需要知道的是消息处理的吞吐量。如果吞吐量容量足以处理您的消息流,则无需担心。