私自身、これにはっきりと答えさせてください。
NSBチーム( http://tech.groups.yahoo.com/group/nservicebus/message/17758 )のAndreasÖhlundの助けを借りて多くの調査を行った後、この質問に対する正しい答えは次のとおりです。
- Udi Dahanが述べたように、設計上、スケールアウトシナリオではディストリビューター/マスターノードのみがタイムアウトマネージャーを実行する必要があります。
- 残念ながら、NServiceBus 3の初期バージョンでは、これは設計どおりに実装されていません。
次の3つの問題があります。
1)ディストリビュータープロファイルを使用して実行しても、タイムアウトマネージャーは起動しません。
回避策:
ディストリビューターに次のコードを含めて、ディストリビューターでタイムアウトマネージャーを自分で起動します。
class DistributorProfileHandler : IHandleProfile<Distributor>
{
public void ProfileActivated()
{
Configure.Instance.RunTimeoutManager();
}
}
マスタープロファイルを実行する場合、タイムアウトマネージャーがマスターノードで自動的に開始されるため、これは問題ではありません。
2)ワーカープロファイルで実行されているワーカーは、それぞれローカルタイムアウトマネージャーを起動します。
これは設計どおりではなく、タイムアウトストアに対するポーリングとタイムアウトのディスパッチを台無しにします。すべてのワーカーは、「MASTERNODEの差し迫ったタイムアウトを教えてください」でタイムアウトストアをポーリングします。W1、W2などではなく、MASTERNODEのタイムアウトを要求していることに注意してください。そのため、複数のワーカーがタイムアウトストアから同じタイムアウトを同時にフェッチすることになり、タイムアウトを削除するときにRavenとの競合が発生する可能性があります。
ディスパッチは、常にLOCAL .timouts / .timeoutsdispatcherキューを介して行われますが、MasterNode/Distributorのタイムアウトマネージャーのキューを介して行われる必要があります。
回避策は、次の両方を行う必要があります。
a)ワーカーのタイムアウトマネージャーを無効にします。このコードをワーカーに含めます
class WorkerProfileHandler:IHandleProfile<Worker>
{
public void ProfileActivated()
{
Configure.Instance.DisableTimeoutManager();
}
}
b)マスターノード/ディストリビューターの.timeoutsキューを使用するように、ワーカーのNServiceBusを再ルーティングします。
これを行わないと、ワーカーでのRequestTimeoutまたはDeferの呼び出しはすべて終了しますが、タイムアウトマネージャーの構成を忘れたという例外があります。これをワーカー構成に含めます。
<UnicastBusConfig TimeoutManagerAddress="{endpointname}.Timeouts@{masternode}" />
3)誤った「準備完了」メッセージがディストリビューターに返されます。
タイムアウトマネージャーは、ディストリビューターストレージキューで使用可能なワーカーからエントリを削除せずに、メッセージをワーカー入力キューに直接ディスパッチするため、ワーカーは、タイムアウトを処理した後、誤った「準備完了」メッセージをディストリビューターに送り返します。これは、1と2を修正した場合でも発生し、タイムアウトがワーカーのローカルタイムアウトマネージャーからフェッチされた場合でも、ディストリビューター/マスターノードで実行されているマネージャーからフェッチされた場合でも違いはありません。その結果、ワーカーによって処理されるタイムアウトごとに、ディストリビューターのストレージキューに余分なエントリが蓄積されます。
回避策:NServiceBus3.3.15以降を使用してください。