Wikipedia 文章描述了消息队列的共同特征,即在给定消息队列实现中可能/可能不可用的功能。
当您将 Rebus 配置为使用 MSMQ 和 RabbitMQ 作为传输时,它将默认使用具有以下属性的设置:
交付政策:自始至终严格至少一次。这是排队系统可以提供的最好保证,因为恰好一次要求排队系统可以在与您正在做的任何工作相同的事务中工作,这是不可能的(至少通常是这样)。
排队标准:当消息被传递到排队系统时,Rebus 认为消息已入队,没有任何例外。对于 RabbitMQ 和 MSMQ,Rebus 将在接收消息时使用的同一队列事务中发送所有传出消息,因此接收/发送操作可以原子地提交给队列系统。
Rebus 默认使用带有消息持久性的 RabbitMQ,这意味着当 RabbitMQ 写入磁盘时,消息被认为已传递。RabbitMQ 可能/可能没有一些我不知道的额外持久性选项,因此可以配置您的 RabbitMQ 服务器以将消息复制到其他节点。
使用 MSMQ,消息在写入磁盘时被视为已送达。由于 MSMQ 在本地运行,这意味着消息在转发到(可能是远程的)接收消息队列之前始终存储在本地。
消息过滤:Rebus 目前没有“过滤”消息的方法,除了订阅感兴趣的消息类型。
收据通知:Rebus 不支持任何类型的收据 - 假设排队系统是可靠且持久的(确实如此,因为 Rebus 仅以可靠和持久的方式使用其传输) - 因此,所有消息都以即发即弃的方式。
bus.Reply
不过,如果您想自己实现某种收据机制,您可以自由使用。
结论:在使用 Rebus 时,这些东西不能(而且很可能不应该)被调整——Rebus 以某种方式使用它的传输来提供它的交付保证,如果你绕过它,你可能会不小心破坏它。
我希望这会有所帮助:)
.
关于传递策略的修正 - 至少一次保证是否意味着接收端必须检查之前是否已收到给定消息:
是的,在某些情况下确实如此——但这取决于您在接收端执行的工作的性质。
在某些情况下,您可能很幸运,该操作本身是幂等的,因此该操作是否执行 1 次或多次并不重要。
在其他情况下,您可能需要存储诸如时间戳之类的域信息,或者甚至可能需要存储一组已处理消息的 ID,以使您的端点以幂等方式工作。
应该注意的是,Rebus 总是在队列事务中处理您的消息,并且如果您在例如数据库中进行自己的工作,在发生异常的情况下您可以回滚您的工作,那么一切都会按应有的方式回滚。
Rebus 最终会两次传递相同消息的唯一情况是发生以下事件序列时:
- 您在队列事务中收到消息
- 您在数据库事务中工作
- 你提交数据库事务
- 队列系统变得不可达,因此无法提交队列事务
在这种情况下,消息将在一段时间后再次传递。在像 MSMQ 这样的队列系统上使用 Rebus,所有进程间通信都在本地进程之间进行,这种事件序列不太可能发生。
应该注意的是,如果您的数据足够重要并且一致性至关重要,那么您必须始终以一种或另一种方式使您的端点具有幂等性。