【问题标题】:Azure Storage Queue - correlate response to requestAzure 存储队列 - 将响应与请求相关联
【发布时间】:2012-03-08 07:42:07
【问题描述】:

当 Web 角色将消息放入存储队列时,它如何轮询特定的相关响应?我希望后端 Worker 角色将消息放入响应队列,目的是让调用者选择响应并从那里开始。

我们的目的是利用队列将一些繁重的处理工作转移到后端 Worker 角色上,以确保 Web 角色的高性能。但是,我们不希望在后端 Worker 完成并响应之前响应 HTTP 请求。

【问题讨论】:

    标签: azure queue message-queue azure-storage


    【解决方案1】:

    我实际上正在做出类似的决定。在我的情况下,我有一个以 Web 角色运行的 WCF 服务,它应该将计算卸载到工作角色。计算出结果后,Web 角色会将答案返回给客户端。

    我的基本数据结构知识告诉我,我应该避免使用以非队列方式设计为队列的东西。这意味着应该始终以类似 FIFO 的方式为队列提供服务。所以基本上如果对请求和响应都使用队列,等待向客户端返回数据的线程将不得不等到计算消息位于响应队列的“顶部”,这不是最佳的。如果使用 Azure 表存储响应,线程会轮询消息,从而产生不必要的开销

    我相信这个问题的一个可能解决方案是使用请求队列。这可以使用竞争消费者模式,从而实现负载平衡。在发送到此队列的消息上,您在消息上设置correlationId property。对于回复,Azure 服务总线的 pub/sub 部分(“主题”)部分与 correlation filter 一起使用。当您的后端处理了请求时,它会将结果发布到“responseSubject”,并使用原始请求中给出的correlationId。现在,您的客户可以通过使用该相关过滤器调用 CreateSubscrition 来检索此响应(对不起,我显然不能发布两个以上的链接,谷歌它),并且它应该在发布答案时得到通知。请注意,CreateSubscriction 部分应该只在 OnStart 方法中完成一次。然后,您可以对该订阅执行 async BeginRecieve ,当其中一个请求的响应可用时,该角色将在给定的回调中得到通知。 correlationId 将告诉您响应是针对哪个请求的。因此,您的最后一个挑战是将此响应返回给持有客户端连接的线程。

    这可以通过使用correlationId(可能是GUID)作为键和响应作为值创建字典来实现。当您的 Web 角色收到请求时,它会创建 guid,将其设置为相关 ID,将其添加到 hashset,将消息发送到队列,然后在 Guid 对象上调用 Monitor.Wait()。然后让主题订阅调用的接收方法将响应添加到字典,然后在同一个 guid 对象上调用 Monitor.Notify()。这会唤醒您的原始请求线程,您现在可以将答案返回给您的客户端(或其他东西。基本上您只是希望您的线程休眠并且在等待时不消耗任何资源)

    【讨论】:

      【解决方案2】:

      Azure 服务总线 上的队列具有更多功能和范例,包括 pub / sub 功能,可以解决跨多个实例处理队列服务的问题。

      使用 pub/sub 的一种方法是有一个队列用于请求,一个队列用于响应。每个请求实例还将订阅响应队列,并在标头上使用过滤器,以便它只接收针对它的响应。请求消息当然会包含放置在响应标头中以驱动过滤器的值。

      【讨论】:

      • 欢迎来到stackoverflow。感谢您的回复,我将检查服务总线选项。我注意到您的其他答案与 Azure 有关。我希望能读到很多像他们一样的人!
      • 感谢您的热烈欢迎。我希望能做出更多的贡献。是的,我目前的经验都与天蓝色有关。
      【解决方案3】:

      对于基于服务总线的解决方案,有一些示例可用于使用 QueuesTopics (pub-sub) 实现请求/响应模式

      【讨论】:

      • 谢谢。它是否具有确保在响应是针对订阅者的同时,响应实际上与原始请求相关联的功能?
      • 与简单队列允许您竞争消息的方式相同,启用会话的服务总线队列允许您竞争会话。您可以在此处指定 SessionId,然后锁定该会话。发送到该会话的任何消息都只会发送给您。因此,如果每个订阅者都有自己的唯一 ID,他们将其用作 SessionID,然后将其作为 ReplyToSessionId 在消息中发送,那么保证响应相关的唯一代码就是我们设置的回复消息:ReplyMessage.SessionId = RequestMessage。回复会话 ID。这种模式显示在示例中。
      • 感谢您的回复。我投票给你。我从@Henrikmh 中选择了答案,因为最后一段关于使用 Dictionary 作为关联机制。我们将有来自同一主机的许多并发请求。 Session 解决了给定主机的订阅问题,但不是针对每个并发请求。我相信您可能已将其作为练习留给读者。 :-)
      【解决方案4】:

      让工作角色继续轮询和处理消息。处理完消息后,在从队列中删除处理后的消息之前,在表存储中添加一个具有所需 corelationId(RowKey) 和处理结果的条目。

      然后 WebRoles 只需要使用所需的 correlationId(RowKey) 和 PartitionKey 来查找表

      【讨论】:

      • 非常酷的想法。我喜欢这种搭配,因为只有发起请求的 Web 角色需要看到响应。我将需要某种垃圾收集器来处理在 Web 角色失败的情况下永远不会弹出的孤立表存储条目。
      • 我认为这不是一个好主意。然后,您基本上是在构建一个新的队列系统(使用表存储),而不是使用 Azure 中的专用队列/主题功能。此外,您还必须轮询表存储以获取响应 = 效率非常低且不可扩展。
      【解决方案5】:

      看看在辅助角色和浏览器客户端之间使用SignalR。因此,您的 Web 角色将消息放入队列并将结果返回给浏览器(类似“等待...”之类的简单操作)并使用 SignalR 将其连接到辅助角色。这样你的网络角色就可以继续做其他事情,而不必等待异步处理的结果,只有浏览器需要。

      【讨论】:

        【解决方案6】:

        Windows Azure 队列没有任何内在特性可以满足您的要求。但是,您可以很容易地自己构建它。在推送到队列中包含消息 ID (GUID),处理完成后,让工作人员将具有该消息 ID 的新消息推送到响应通道队列中。您的 Web 应用可以轮询此队列以确定给定命令的处理何时完成。

        我们已经做了类似的事情,并且正在寻求使用 SignalR 之类的东西来帮助在命令完成时回复客户端。

        【讨论】:

        • 这就是我的想法。我们已经包含了一个 Correlation Id GUID 策略,但在 Web 角色拉取不相关响应的响应队列上似乎有很多轮询。当我调用 GetMessage() 时,有没有办法在它不是我正在等待的响应的情况下快速释放它?或者,或者,也许我可以给每个 Web 角色实例一个专用队列。即使那样,这些队列也不是 FIFO,所以我仍然需要检查该关联 ID。想法?
        • 如果你有多个 webrole 实例(或者甚至在同一个 web 角色上运行的差异请求),则有可能会选择用于实例 1 的消息通过实例 2,它将检查相关 id,意识到它没有等待它并且必须将它放回队列中。我已经尝试过了,但它不能很好地扩展。桌子的想法要好得多。
        • 感谢您添加此评论。考虑到 IIS 可以在同一个机器上同时处理许多请求,我很担心这一点。
        • 在这种情况下,回复队列必须与您的 Web 前端为 1:1。您可以让每个 webrole 启动并创建它自己的队列。 table 选项很有趣,但是如果您不知道请求何时到来,您最终会查询很多。弹出消息意味着您所做的事情得到了回应。
        • @dunnry 1:即使使用 1:1 映射,Web 角色不能有多个并行运行的请求,通过队列传递到后端吗?如果是这样,它仍然需要检查 Correlation Id,因为即使它有一个专用队列,它也不能保证它从队列中提取的消息来自特定的请求。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-10
        • 1970-01-01
        • 2018-02-19
        • 2016-11-23
        • 1970-01-01
        • 2017-11-04
        • 1970-01-01
        相关资源
        最近更新 更多