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

时间:2011-11-03 22:00:21

标签: .net networking architecture scalability parallel-processing

我正在为一个项目设计服务器守护程序,该守护程序必须同时接收大量的请求并进行异步处理。我知道这个项目规模庞大,但我对此非常认真,并且在进一步研究之前,我正在尝试制定清晰的设计和计划。

以下列出了我的目标:

  • 可扩展性 - 必须能够将架构并行化到多个处理器甚至多个服务器上。
  • 能够应对大量并行连接。
  • 如果单个请求需要很长时间才能处理,则不得导致阻塞问题。
  • 要求响应周转时间必须极短。
  • 围绕.NET框架构建(将在C#中编写)

我提出的架构和流程相当复杂,所以这里是我最初设计的图表:

Architecture Flow Chart

(以及here it is on tinypic以防它严重调整大小)

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

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

  1. 立即 - 顾名思义,立即请求会立即处理。

  2. 可延迟 - 可延迟请求被视为低优先级。它们在低负载期间立即处理,或者在负载较高时置于延迟请求队列(DRQ)中。负载均衡器从DRQ获取这些延迟的请求,将它们标记为立即,然后将它们放回适当的RQ中。

  3. 定时 - 将定时请求与其目标时间戳一起放入定时请求队列(TRQ)。这些请求通常是由于另一个请求而生成的,而不是由客户端明确发送的。超过请求时间戳时,下一个可用的请求处理器线程将使用它并对其进行处理。

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

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

    我正在寻找的是一些领域的建议:

    • 我错过了这个架构有什么重大缺陷吗?
    • 出于性能原因,有什么我应该考虑改变的吗?
    • TCP或UDP是否更适合请求?拥有TCP提供的“交付证明”非常有用,但UDP的轻量级特性也很吸引人。
    • 在Windows服务器上处理100k +同时连接时,我需要考虑哪些特殊注意事项?我知道Linux的TCP堆栈处理得很好,但我对Windows不太确定。
    • 我还有其他问题要问吗?我忘了考虑任何事情吗?

    我知道这有很多东西要读,也可能要求很多,所以谢谢你的时间。

    图表here的更新版本。

3 个答案:

答案 0 :(得分:2)

您还可以考虑以下内容:

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

PS:我还建议好书“Enterprise Integration Patterns

答案 1 :(得分:1)

我不明白为什么你需要多个请求队列。在我看来,您只需要一个请求队列,许多处理器都从中读取。它不应该是任何队列系统的问题。只有一个队列可以将输入与处理器分离,从而实现更好的可扩展性 - 在需要时启动更多处理器,没有其他人需要关心它。

至于TCP与UDP - 您在寻找什么样的性能?使用ZeroMQ等现有通信基础设施来为您处理这些技术问题不是更好吗?

伊泰。

答案 2 :(得分:0)

如果您希望扩展得非常好,则需要确保所有组件可扩展 - 处理元素,输入/输出部分和队列。如果您打算在Microsoft堆栈上执行此操作,我会认真考虑研究Windows Azure,它提供了您需要的大部分(如果不是全部)关键功能。你没有提到的一件事 - 是否会有持久存储层(例如数据库)?如果是这样,那么也要准备好进行扩展,否则它将成为你的单点失败。