【问题标题】:Nservicebus Sequence服务总线序列
【发布时间】:2015-12-11 00:31:49
【问题描述】:

我们要求所有消息都按照到达 MSMQ 的顺序进行处理。

我们将向客户端公开 WCF 服务,该 WCF 服务将使用 NServiceBus(Sendonly 总线)将消息发布到 MSMQ。

我们要开发一个windows服务(MessageHandler),它会使用Nservicebus从MSMQ中读取消息并保存到数据库中。我们的数据库每天有几个小时不可用。

在数据库停机期间,我们希望进程重试 MSMQ 中的第一条消息并停止处理其他消息,直到数据库启动。一旦数据库启动,我们希望 NServicebus 按照消息发送的顺序进行处理。

设置 MaximumConcurrencyLevel="1" MaximumMessageThroughputPerSecond="1" 在这种情况下会有帮助吗?

使用 NServiceBus 处理这种情况的最佳方法是什么?

【问题讨论】:

    标签: wcf msmq nservicebus nservicebus5


    【解决方案1】:

    我们要求所有消息都在 到达 MSMQ 的顺序。

    查看这个问题的答案How to handle message order in nservicebus?,以及这篇帖子here

    我同意,虽然可以按订单交付,但最好将您的系统设计成订单无关紧要。链接的文章概述了以下解决方案:

    • 为所有消息添加序列号
    • 在接收器中检查序列号是最后看到的数字 + 1,如果没有抛出一个乱序异常
    • 启用二级重试(因此,如果它们出现故障,他们希望在收到正确消息后稍后重试)

    但是,为了回答您的具体问题:

    将设置MaximumConcurrencyLevel="1" MaximumMessageThroughputPerSecond="1" 在这种情况下有帮助吗?

    不是真的。

    只要您需要按顺序交付,基本的逻辑法则就规定,在您的消息处理管道的某个地方,您必须有一个单线程进程,以保证按顺序交付。

    这取决于您(查看resequencer pattern),但您当然可以将 NserviceBus 处理程序限制为单个线程(我认为您不需要设置 MaximumMessageThroughputPerSecond 以使其成为单线程) .

    但是,即使您这样做了,并且即使您使用了事务队列,您仍然不能保证每条消息都会出列并按顺序处理到数据库中,因为如果任何消息出现任何永久性故障它们将从队列中移除并处理下一条消息。

    在数据库停机期间,我们希望进程重试第一个 MSMQ 中的消息并停止处理其他消息,直到数据库 起来了。一旦数据库启动,我们希望 NServicebus 在 命令发送消息。

    不建议这样做。 NServiceBus 中的第二级重试功能旨在处理意外和短期中断,而不是计划和长期中断。

    对于初学者,当您的 NServiceBus 消息处理程序端点尝试处理其输入队列中的消息并发现数据库不可用时,它将实施其第二级重试策略,默认情况下将尝试出队 5 次,频率增加,并且然后永久失败,将失败的消息留在它的错误队列中。然后它将移动到输入队列中的下一条消息。

    虽然这本身并不违反您的按订单交付要求,但由于两个原因,这会让生活变得非常困难:

    1. 一旦数据库再次可用,将需要优先重新处理永久失败的消息,并且
    2. 会有大量不需要的故障日志记录,这会混淆任何真正的处理错误。

    如果您事先知道有定期计划的中断,那么处理它们的最简单方法是实施服务窗口,这是计划的另一个术语。

    但是,Windows 服务管理器不支持服务窗口的概念,因此您必须使用计划任务停止然后启动服务,或者查看其他选项,例如hangfirequartz.net 或其他一些cron-type 图书馆。

    【讨论】:

    • 非常感谢汤姆。这真的很有用。
    【解决方案2】:

    这取决于您为什么需要消息按顺序到达。如果就像你先收到Order消息,然后是各种OrderLine消息,都属于某个顺序,有多种可能。

    一个是接受OrderLine 消息没有OrderOrder 无论如何都会稍后出现。最终的一致性。

    另一个是在 NServiceBus Saga 中收集消息(和可能的状态)。当通常MessageA 需要先到达,只有稍后接收MessageBMessageC 时,才让所有三个消息都能够启动saga。所有这三个消息都需要将它们联系在一起,例如唯一的 GUID。然后 saga 将确保正确收集它们,当所有消息都到达时,可能会存储其最终状态并将 saga 标记为已完成。

    另一种选择是将所有消息直接保存到数据库中,并让其他东西找出属于什么的。对于数据仓库来说,这是一个有用的场景,无论如何都需要收集数据。有些数据可能不是 100% 准确(或一致),但没关系。

    异步消息传递很难 100% 按顺序处理它们,尤其是当调用 WCF 的客户端出错和/或无序发送它们时。这不是我第一次有这样的要求和乱序的消息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-25
      • 1970-01-01
      • 2015-07-18
      • 2019-02-12
      • 2021-11-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多