请允许我自己清楚地回答这个问题。
经过大量挖掘并在 NSB 团队的 Andreas Öhlund 的帮助下(http://tech.groups.yahoo.com/group/nservicebus/message/17758),这个问题的正确答案是:
- 就像 Udi Dahan 提到的那样,根据设计,只有分发器/主节点应该在横向扩展场景中运行超时管理器。
- 不幸的是,在 NServiceBus 3 的早期版本中,这并没有按设计实现。
您有以下 3 个问题:
1) 使用 Distributor 配置文件运行不会启动超时管理器。
解决方法:
通过在分发服务器上包含以下代码,您自己在分发服务器上启动超时管理器:
class DistributorProfileHandler : IHandleProfile<Distributor>
{
public void ProfileActivated()
{
Configure.Instance.RunTimeoutManager();
}
}
如果您运行主配置文件,这不是问题,因为超时管理器会自动为您在主节点上启动。
2) 使用 Worker 配置文件运行的 Worker 每个都启动一个本地超时管理器。
这与设计不符,并且会扰乱对超时存储的轮询和超时分派。所有工作人员都使用“给我 MASTERNODE 即将超时”来轮询超时存储。请注意,他们要求 MASTERNODE 的超时,而不是 W1、W2 等。因此,多个工作人员最终可能会同时从超时存储中获取相同的超时,从而导致在从中删除超时时与 Raven 发生冲突。
调度总是通过 LOCAL .timouts/.timeoutsdispatcher 队列发生,而它应该通过 MasterNode/Distributor 上的超时管理器的队列进行。
解决方法,您需要同时执行以下操作:
a)禁用工人的超时管理器。将此代码包含在您的工人身上
class WorkerProfileHandler:IHandleProfile<Worker>
{
public void ProfileActivated()
{
Configure.Instance.DisableTimeoutManager();
}
}
b) 在工作人员上重新路由 NServiceBus 以使用 MasterNode/Distributor 上的 .timeouts 队列。
如果你不这样做,任何对 worker 的 RequestTimeout 或 Defer 的调用都将终止,并出现一个异常,指出你忘记配置超时管理器。将此包含在您的工作人员配置中:
<UnicastBusConfig TimeoutManagerAddress="{endpointname}.Timeouts@{masternode}" />
3) 错误的“就绪”消息返回给分销商。
因为超时管理器将消息直接分派到工作人员输入队列,而不从分发服务器存储队列中的可用工作人员中删除条目,所以工作人员在处理超时后将错误的“就绪”消息发送回分发服务器。即使您已经修复了 1 和 2,也会发生这种情况,并且如果超时是从 worker 上的本地超时管理器或在分发器/MasterNode 上运行的一个超时管理器获取的,则没有区别。结果是在分配器上的存储队列中为工人处理的每个超时建立一个额外的条目。
解决方法:使用 NServiceBus 3.3.15或更高版本。