我正在为一个项目设计服务器守护程序,该守护程序必须同时接收大量的请求并进行异步处理。我知道这个项目规模庞大,但我对此非常认真,并且在进一步研究之前,我正在尝试制定清晰的设计和计划。
以下列出了我的目标:
我提出的架构和流程相当复杂,所以这里是我最初设计的图表:
(以及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达到其最大大小,则所有请求处理器线程都将暂停。这将通过信号量来实现,信号量还应该阻止单个请求处理器线程被阻塞并留下过时的请求。
我正在寻找的是一些领域的建议:
我知道这有很多东西要读,也可能要求很多,所以谢谢你的时间。
图表here的更新版本。
答案 0 :(得分:2)
您还可以考虑以下内容:
PS:我还建议好书“Enterprise Integration Patterns”
答案 1 :(得分:1)
我不明白为什么你需要多个请求队列。在我看来,您只需要一个请求队列,许多处理器都从中读取。它不应该是任何队列系统的问题。只有一个队列可以将输入与处理器分离,从而实现更好的可扩展性 - 在需要时启动更多处理器,没有其他人需要关心它。
至于TCP与UDP - 您在寻找什么样的性能?使用ZeroMQ等现有通信基础设施来为您处理这些技术问题不是更好吗?
伊泰。
答案 2 :(得分:0)
如果您希望扩展得非常好,则需要确保所有组件可扩展 - 处理元素,输入/输出部分和队列。如果您打算在Microsoft堆栈上执行此操作,我会认真考虑研究Windows Azure,它提供了您需要的大部分(如果不是全部)关键功能。你没有提到的一件事 - 是否会有持久存储层(例如数据库)?如果是这样,那么也要准备好进行扩展,否则它将成为你的单点失败。