用于昂贵请求的请求聚合器/中间层设计模式
本文关键字:请求 中间层 设计模式 用于 | 更新日期: 2023-09-27 17:53:30
我正在研究一个程序,该程序将有多个线程需要来自web服务的信息,可以处理以下请求:"用[Var1, Var2, Var3]
换[Object1, Object2, ... Object20]
"
和结果的回复将给我一个,在本例中,20个节点的XML(每个对象一个),每个节点有3个子节点(每个变量一个)。
我的挑战是,这个web服务的每个请求都要花费组织的钱,无论是1个对象的1个变量还是20个对象的20个变量,成本都是一样的。
所以,在这种情况下,我正在寻找一个架构,将:
- 在每个线程上创建一个需要数据的请求
- 有一个中间层的"聚合器"来获取所有的请求
- 一旦聚合了X数量的请求(或达到了时间限制),中间层执行web服务的单个请求
- 中间层接收到web-service的应答
- 中间层路由信息返回到等待对象
目前,我的想法是使用像NetMQ这样的库,我的中间层作为服务器,每个线程作为轮询器,但我在实际实现中卡住了,在深入兔子洞之前,我希望已经有一个设计模式/库,它比我想象的要有效得多。
请理解,我是一个新手,所以,任何帮助/指导将是非常感激的!!
谢谢! !
概述
从体系结构的角度来看,您刚刚为这个问题勾画出了一个很好的方法:
- 在请求应用程序和远程web服务之间插入代理
- 在代理中,将请求放入请求队列,直到至少发生以下事件之一
- 请求队列达到给定长度
- 请求队列中最老的请求达到一定年龄
- 将请求队列中的所有请求分组为一个请求,删除重复的对象或属性
- 将此请求发送到远程web服务
- 将请求移动到(等待)响应队列
- 等待响应,直到出现以下情况之一
- 响应队列中最老的请求达到一定年龄(超时)
- 响应到达
- 获取响应(如果适用)并将其映射到响应队列中的相应请求
- 响应队列中具有应答 的所有请求
- 为所有超过超时限制的请求发送超时错误
- 从响应队列中删除所有已应答的请求
你可能找不到一个现成的产品或框架完全符合你的需求。但是有几个框架/架构模式可以用来构建解决方案。
c#: RX and LINQ
当你想使用c#时,你可以使用响应式扩展来获得正确的计时和分组。
然后,您可以使用LINQ从请求中选择属性来构建响应,并在响应队列中选择与响应的特定部分匹配或超时的请求。
Scala/Java: Akka
您可以将解决方案建模为一个参与者系统,使用几个参与者:
- 作为请求的网关的参与者
- 持有请求队列的参与者
- 向远程web服务发送请求并获得响应的参与者
- 持有响应队列的参与者
- 发送响应或超时的参与者
参与者系统使并发处理和以可测试的方式分离关注点变得容易。
当使用Scala时,你可以使用它的"一元"集合API (filter
, map
, flatMap
)来做与c#方法中的LINQ基本相同的事情。
当您想要测试单个元素时,actor方法确实很好用。单独测试每个参与者是非常容易的,而不必模拟整个工作流程。
Erlang/Elixir: Actor System
这类似于Akka方法,只是使用了不同的(函数式的!)语言。Erlang/Elixir对分布式参与者系统有很多支持,所以当你需要一个超级稳定或可扩展的解决方案时,你应该考虑一下这个。
NetMQ/ZeroMQ
这可能是太低的水平,并带来了很少的基础设施。当您使用参与者系统时,您可以尝试引入NetMQ/ZeroMQ作为传输系统。
标题>我觉得你使用队列的想法不错。
这是你问题的一个可能的解决方案,我相信还有无数其他的解决方案可以满足你的需要。
- 有一个"发布队列"(PQ)和一个"消费队列"(CQ)
- 客户端订阅CQ, MT订阅PQ
- 客户端向PQ发布请求
- MT监听PQ,聚合请求和调度到线程中的farm
- 一旦结果返回,该线程将结果分离到req/res对 然后将请求/res对发布到CQ
- 每个客户端选择正确的消息并处理它
长(er)版本:
让你的"中间层"监听一个队列(客户端向其发布消息)并聚合请求,直到N个请求通过或X个时间过去。
准备好后,将聚合的请求卸载到一个线程来调用您的farm并获得结果。当您需要将此信息反馈给客户端时,很可能会出现更大的问题。
为此,您可能需要另一个所有客户端都订阅的队列,一旦您的结果批处理就绪(例如20个XML响应),调用该队列的线程将把XML结果分离到相应的请求/响应对中,并发布到该队列。每个客户端都需要从队列中获取正确的请求/响应对并对其进行处理。
这将不是传统意义上的web服务,因为等待时间可能会非常长,并且您不想维护连接,这就是我建议使用队列的原因。
你也可以让你的消费者队列是基于主题的,这意味着你只发布请求的req/res对的消费者,而不广播它(所以客户端不必"选择正确的req/res")。它将根据主题名称进行处理)。