1

我们需要按照到达 MSMQ 的顺序处理所有消息。

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

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

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

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

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

4

2 回答 2

1

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

一种是接受OrderLine没有Order. Order反正以后会进来的。最终的一致性。

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

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

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

于 2015-09-16T22:10:25.917 回答
1

我们需要按照到达 MSMQ 的顺序处理所有消息。

请参阅此问题的答案How to handle message order in nservicebus? ,还有这个帖子在这里

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

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

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

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

并不真地。

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

发生这种情况取决于您(查看重新排序器模式),但您当然可以将 NserviceBus 处理程序限制为单个线程(我认为您不需要设置 MaximumMessageThroughputPerSecond 以使其成为单线程)。

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

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

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

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

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

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

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

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

于 2015-09-15T09:18:27.287 回答