异步服务器设计

Posted

技术标签:

【中文标题】异步服务器设计【英文标题】:Asynchronous server design 【发布时间】:2013-06-06 14:26:18 【问题描述】:

我们有一个服务器从 500-1500 个 GPS 设备接收数据。每个设备每 10-30 秒发送一个包含大约 1-4 个 GPS 坐标的数据包。服务器是异步设计的,侦听器使用 Begin-EndAccept 处理连接,并使用 Begin-EndReceive 进行通信。一旦接收到数据包,数据就会被处理并存储在数据库中。

对于少数设备(500-700 台设备),这仅需要 50 毫秒,并且我们运行的并发线程少于 50 个,并且 CPU 使用率是真实的 (20-40%)。但是,当服务器受到连接(1000+)的压力时,线程数会激增至 500-600,CPU 使用率也会下降到百分之几。处理时间也增加到几分钟。

异步设计是否不适合这种特定场景,许多小数据包以这种速率发送,或者可能是代码中的问题?

我们目前不得不将负载分布在三台服务器上以容纳所有设备,它们都是托管在 Hyper-V 服务器上的具有 6 个 CPU 和 4GB 内存的 VM。

解决方案:

我从人们的回答中找到的解决方案是立即使用 .Net 并行库将其安排为任务,因为这在跨多个内核调度线程时要聪明得多:

void EndReceive(IAsyncResult res)

   Task.Factory.StartNew((object o) =>  HandleReceive(o as IAsyncResult); , res, TaskCreationOptions.PreferFairness);

现在线程很少超过 50。

【问题讨论】:

听起来您可能遇到了最大连接池大小的限制。我猜它是网络服务器和数据库之间的连接。解决方案可能就像增加最大连接池大小一样简单,但您可能还需要考虑让 Web 服务器将其接收的数据排队,然后将其分批发送到数据库。 考虑不处理和存储数据异步。您能否接收数据,将其放入队列中,然后向设备确认。可以使用 BlockingCollection 来处理和写入数据库。我会在单独的步骤中执行此操作,以便您可以针对具体情况进行优化。例如。并行处理。不要并行数据库写入。如果您有 500 个线程写入同一个表,那么您可能有 499 个线程在等待锁定。一个智能线程通常是写入数据库的最佳方式。或者只是验证输入数据并响应设备。 【参考方案1】:

听起来您在应用程序的某个地方使用了非异步 IO,您在其中阻塞了操作的结果。您可能在许多地方都使用了适当的异步,例如从服务器与客户端的主要连接,但在连接到数据库或类似的东西时,您可能没有使用。异步和非异步的这种混合可能是您创建如此多线程的原因。

通过确保您有 no 阻塞 IO,它应该确保您没有很多线程池线程无所事事,这似乎是您所处的情况。

【讨论】:

这似乎是一个可能的原因,所以我会接受答案。我的解决方案是立即使用 .Net 并行库将其安排在任务上【参考方案2】:

你在服务器上做什么样的操作?

如果它们是受 CPU 限制的,那么拥有比内核更多的线程是没有用的,并且添加更多线程可能会使您的服务器变得混乱,一堆线程像狗一样争吵;)

在这种情况下,您应该更幸运地使用简单的处理循环,每个内核一个。

【讨论】:

【参考方案3】:

我从来没有同时处理过这么多的请求,但是您可以尝试创建与 CPU 上的内核一样多的线程,然后实现排队系统。您的线程将一次消耗队列一个设备的坐标。这样我猜你的 CPU 会全速使用......

【讨论】:

以上是关于异步服务器设计的主要内容,如果未能解决你的问题,请参考以下文章

架构设计|异步请求如何同步处理?

中间层异步 WCF 服务调用和向 UI 层返回数据的质量设计

爬虫日记(94):Twisted的reactor设计来源

服务器设计

Linux(程序设计):65---同步HTTP请求异步HTTP请求

184 - 异步执行器设计和配置