请求针对代价高昂的请求的聚合器/中间层设计模式

时间:2015-06-05 13:09:36

标签: java c# multithreading design-patterns zeromq

我正在开发一个程序,该程序将有多个线程需要来自Web服务的信息,该服务可以处理以下请求: “为[Var1, Var2, Var3]

提供[Object1, Object2, ... Object20]

并且得到的回复将给出一个,在这种情况下,20个节点的XML(每个对象一个),每个节点有3个子节点(每个var一个)。

我的挑战是,这个网络服务的每个请求都要花费组织资金,无论是1个对象的1个变量还是20个对象的20个变量,成本是相同的。

所以,就是这样,我正在寻找一种架构:

  1. 在需要数据时在每个线程上创建请求
  2. 拥有一个获得所有请求的中间层“聚合器”
  3. 一旦聚合了X个请求(或达到了时间限制),中间层就会执行单个Web服务请求
  4. 中间层收到来自网络服务的回复
  5. 中间层将信息路由回等待对象
  6. 目前,我的想法是使用NetMQ这样的库,我的中间层作为服务器,每个线程作为一个轮询器,但是我在实际的实现上陷入困境,在走得太远之前在兔子洞里面,我希望已经有一个设计模式/库,这比我想象的更有效率。

    请理解我是菜鸟,所以,任何帮助/指导都会非常感激!!

    感谢!!!

2 个答案:

答案 0 :(得分:2)

概述

从架构的角度来看,您只是勾勒出一个解决问题的好方法:

  1. 在请求的应用程序和远程Web服务之间插入代理
  2. 在代理中,将请求放入请求队列中,直到发生以下至少一个事件
    1. 请求队列达到给定长度
    2. 请求队列中最早的请求达到特定年龄
  3. 在一个请求中将请求队列中的所有请求分组,删除重复的对象或属性
  4. 将此请求发送到远程Web服务
  5. 将请求移至(等待)响应队列
  6. 等待响应,直到出现以下情况之一
    1. 响应队列中最早的请求达到某个年龄(超时)
    2. 响应到达
  7. 获取响应(如果适用)并将其映射到响应队列中的相应请求
  8. 回答响应队列中有答案的所有请求
  9. 为超过超时限制的所有请求发送超时错误
  10. 从响应队列中删除所有已回答的请求
  11. 技术

    您可能找不到与您的要求完全匹配的现成产品或框架。但是,您可以使用几种框架/架构模式来构建解决方案。

    C#:RX和LINQ

    如果您想使用C#,可以使用reactive extensions来获取时间和分组权限。

    然后,您可以使用LINQ从构建响应的请求中选择属性,并选择响应队列中与响应的某个部分匹配或超时的请求。

    Scala / Java:Akka

    您可以使用多个演员将解决方案建模为演员系统:

    1. 演员作为请求的网关
    2. 持有请求队列的演员
    3. 将请求发送到远程Web服务并获取响应的actor
    4. 持有响应队列的演员
    5. 发送回复或超时的演员
    6. 演员系统可以轻松处理并发并以可测试的方式分离关注点。

      使用Scala时,您可以使用其“monadic”集合API(filtermapflatMap)与C#方法中的LINQ基本相同。

      当您想要测试单个元素时,actor方法真的很棒。这很简单to test each actor individually,无需模拟整个工作流程。

      Erlang / Elixir:演员系统

      这类似于Akka方法,只是使用不同的(功能!)语言。 Erlang / Elixir对分布式actor系统有很多支持,所以当你需要一个超稳定或可扩展的解决方案时,你应该研究一下。

      NetMQ / ZeroMQ

      这可能是太低的水平,并导致很少的基础设施。当您使用actor系统时,您可以尝试将NetMQ / ZeroMQ作为传输系统。

答案 1 :(得分:1)

您使用队列的想法对我来说很好。

这是解决您问题的一种可能方案,我确信无数其他解决方案可以满足您的需求。

  1. 拥有“发布队列”(PQ)和“消费队列”(CQ)
  2. 客户订阅CQ,MT订阅PQ
  3. 客户将请求发布到PQ
  4. MT收听PQ,将请求和调度聚合到一个线程中的场
  5. 一旦结果返回,该线程将结果分成req / res pair
  6. 然后它将req / res对发布到CQ
  7. 每个客户选择正确的消息并对其进行处理
  8. 长(呃)版本:

    让您的“中间层”收听队列(客户端向其发布消息)并聚合请求,直到N个请求通过或X时间已过。

    您已准备就绪,将聚合请求卸载到线程以调用您的服务器场并获取结果。当您需要将此信息传达给客户时,最有可能出现更大的问题。

    为此,您可能需要所有客户端订阅的另一个队列,并且一旦您的结果批处理准备就绪(例如,XML中的20个响应),调用服务器场的线程就会将XML结果分成相应的请求/响应对并发布到此队列。每个客户端都需要从队列中获取正确的请求/响应对并进行处理。

    这不是传统意义上的网络服务,因为等待时间可能过长而你不想保持连接,这就是我建议队列的原因。

    您还可以让您的消费者队列基于主题,这意味着您只需将req / res对发布给要求它的消费者,而不是广播它(因此客户端不必“选择正确的req / res“。将根据主题名称进行处理。几乎所有队列都支持这一点。