.net - 处理服务中传入请求的体系结构

标签 .net networking architecture scalability parallel-processing

我正在为一个项目设计服务器守护程序,该项目必须处理大量并发请求并异步处理它们。我知道这样一个项目的规模很大,但是我对此很认真,并在进一步进行之前试图做出清晰的设计和计划。

这是我的目标清单:


可伸缩性-必须能够将架构并行化到多个处理器甚至多个服务器上。
能够应付大量并行连接。
如果单个请求需要很长时间才能处理,则决不能引起阻塞问题。
请求响应周转时间必须最短。
围绕.NET框架构建(将使用C#编写)


我提出的架构和流程相当复杂,因此以下是我的初始设计的图表:



(以及here it is on tinypic,以防其大小调整不正确)

这个想法是,请求是通过网络传入的(尽管我还没有决定TCP还是UDP是最好的),然后立即传递给高速负载均衡器。然后,负载均衡器使用加权随机数生成器选择一个请求队列(RQ)来放置请求。权重是从每个队列的大小得出的。使用加权RNG而不是仅将请求放入最不繁忙的队列中的原因是,它可以防止空的但阻塞的队列(由于挂起的请求)锁定整个服务器。如果所有RQ都超过一定大小,则负载平衡器将丢弃请求,并将“服务器太忙”响应放入输出队列(OPQ)-此部分未在图中显示。

每个队列对应一个线程,该线程的相似性设置为服务器上的一个CPU内核。这些线程是并行请求处理器的一部分,并行处理器处理来自每个队列的请求。这些请求分为以下三种类型之一:


立即-顾名思义,立即处理立即请求。
可延迟-可延迟请求被认为是低优先级。在低负载期间将立即对其进行处理,如果负载较高,则将它们放入延迟请求队列(DRQ)中。负载平衡器从DRQ中提取这些延迟的请求,将它们标记为立即请求,然后将它们放回适当的RQ中。
定时-定时请求连同其目标时间戳一起放入定时请求队列(TRQ)。这些请求通常是另一个请求的结果,而不是由客户端显式发送的。当超过请求时间戳时,下一个可用的请求处理器线程将使用它并对其进行处理。


处理请求时,可以从内存中的键/值对缓存,键/值对缓存或磁盘上或从专用SQL数据库服务器中获取数据。缓存的值将是BSON,索引将是一个字符串。我正在考虑使用Dictionary<T1,T2>在内存中实现此功能,并为磁盘缓存使用btree(或类似功能)。

处理完成后创建响应,并将其放入输出队列(OPQ)中。然后,循环将消耗来自OPQ的响应,并将其通过网络发送回客户端。如果OPQ达到其最大大小的80%,则将暂停四分之一的请求处理器线程。如果OPQ达到其最大大小的90%,则将暂停一半的请求处理器线程。如果OPQ达到其最大大小,则所有请求处理器线程都将暂停。这将通过信号量来实现,该信号量还应防止单个请求处理器线程被阻塞并留下陈旧的请求。

我在寻找一些方面的建议:


我错过了此体系结构的主要缺陷吗?
出于性能原因,我是否应该考虑更改任何内容?
TCP或UDP更适合请求吗?拥有TCP提供的“交付证明”将非常有用,但是UDP的轻量级特性也很有吸引力。
在Windows Server上处理100k +并发连接时,是否需要考虑一些特殊的考虑?我知道Linux的TCP堆栈处理得很好,但是我不太确定Windows的情况。
我还有其他问题要问吗?我忘了考虑什么吗?


我知道要阅读的内容很多,可能要问的也很多,所以感谢您的宝贵时间。

here的更新版本。

最佳答案

您也可以考虑以下几点:


故障转移。您可以设计一种在可能的服务崩溃时持久保留请求的方法,以便即使在服务重启后,所有待处理的请求也将得到处理
错误队列。 (也称为Dead Letter Channel模式)
Pipes and Filters。通过提供这样的功能,您将获得服务的高度灵活性和可扩展性
请求确认。在某个预定义的时间间隔中,客户端向服务发送了一个请求,等待将CorrelationId设置为初始RequestId的Ack消息,这样,如果客户端未收到特定请求,则服务可以通知客户端已接收到特定请求并将其放入入站队列中。接收刚刚发送的请求的确认-它可以重新发送该请求或将其标记为失败。


PS:我也建议伟大的书“ Enterprise Integration Patterns

关于.net - 处理服务中传入请求的体系结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8002442/

相关文章:

c# - 编程字符串的表单资源使用情况?

java - 进程池的应用程序级负载平衡器

javascript - 我可以将 Angular 2 引入现有的 JS/jQuery/PHP 项目吗?

ruby-on-rails - 如何锁定表以防止在 Rails 中使用记录创建?

design-patterns - 一些架构模式的简单代码实现

c# - 当字符串长度大于 32768 个字符时,.net 序列化器反序列化失败

C# - 如何解析 http header multipart

c# - 我的 C# 程序被检测为病毒?

powershell - 使用Powershell在断开连接的网卡上设置静态IP,是否可以?

c++ - 如何从 TCP 连接获取正确的 MAC 地址?