异步服务器设计
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 层返回数据的质量设计