我最近一直在阅读有关消息传递系统的内容,并专门研究了RabbitMQ和NServiceBus。正如我所理解的那样,如果某条消息由于某种原因而失败,则会再次尝试一次。然后,两个系统都提供了稍后再试的可能性,例如在5秒内。五秒钟过后,消息会再次发送多次。
我在Implementing Domain-Driven Design(p.502)中引用Vaughn Vernon:
处理此问题的另一种方法是简单地重试发送直到成功,可能使用上限指数退避。在RabbitMQ的情况下,重试可能会失败很长一段时间。因此,使用消息NAK和重试的组合可能是最好的方法。不过,如果我们的流程每五分钟重试三次,那么它可能就是我们所需要的。
对于NServiceBus,这称为二级重试,当重试发生时,它会多次发生。
为什么需要多次发生?为什么每五分钟不重试一次?五分钟后第一次重试失败的可能性是多少,第二次重试(可能只是几毫秒后)应该成功?
如果由于某些配置它不需要(是吗?),为什么我找到的所有示例都有多次重试?
答案 0 :(得分:5)
我的背景是NServiceBus所以我的回答可能就是那些用语。
对于非常短暂的错误,第一级重试非常有用。死锁就是一个很好的例子。您尝试更改数据库,并选择您的事务作为死锁牺牲品。在这些情况下,第一级重试是完美的。 大部分时间,只需要进行一次第一级重试。如果数据库中存在大量争用,那么重试2或3次就足够了。
第二级重试适用于不太短暂的错误。考虑诸如Web服务停机10秒或故障转移群集切换中的SQL Server数据库之类的事情,这可能需要30-60秒。如果你在几毫秒之后重试,它对你没有任何好处,但10,20,30秒后你可能会有一个好的镜头。
然而,问题的关键是在第一次重试5次之后再延迟,为什么在额外延迟之前再试一次5次?
首先,在您的第一次二级重试时,您仍然可能遇到死锁或其他非常短暂的错误。毕竟,目标通常不要使系统尽可能慢,因此如果问题确实是暂时的,那么在重试之前不必等待额外的延迟。当然,基础设施无法知道问题的暂时性。
第二个原因是,如果它们完全相同,则更容易配置。每个级别的X级重试次数和Y次尝试次数= X * Y总次数,配置文件中只有2个数字。在NServiceBus中,这是2个值加上退避时间跨度,所以配置如下所示:
<SecondLevelRetriesConfigEnabled="true" TimeIncrease ="00:00:10" NumberOfRetries="3" />
<TransportConfig MaxRetries="3" />
这很简单。试试3次。等10秒钟。试试3次。等20秒。试试3次。等30秒。试试3次。然后你就完成了,然后你就转到了一个错误队列。
为每个级别配置不同的值需要更复杂的配置故事。
答案 1 :(得分:3)
存在第一级重试以补偿网络和数据库锁等快速问题。这可以在NSB中配置,因此如果您不想要它们,可以将它们关闭。二级重试是为了弥补更长时间的中断。例如,我们使用SLR来补偿每晚同时回收的数据库。
OOTB功能增加了SLR之间的持续时间,因为它假设如果它在上一次不起作用,则需要更多时间来修复它。存在可覆盖的重试策略,因此您可以更改SLR的工作方式。
在NSB中,除非事务在FLR之后仍然失败,否则FLR始终排在第一位且SLR不起作用。此外,您可以完全禁用SLR并构建自己的自定义故障管理器,它具有额外的功能。我们有一个流程,我们有一个故障管理器,可以将问题发送给员工帮助台,因为这是解决特定问题子集的唯一方法。