2016-05-26 8 views
2

SQL Serverの2014データベースはREAD_COMMITTED_SNAPSHOTに設定されています。MSMQとSQL Serverで分散トランザクションが発生することがありますが、ダーティリードが発生することがあります。

我々は、すべての下に(キューに新しいメッセージを公開し、データベースの更新を行い、我々はキューからのメッセージを読んで、私たちのシステムの一部ではMSMQと分散トランザクション(私たちはMassTransit 2.10を使用)

を使用し、単一トランザクション)。

次のメッセージが処理されたときに更新がコミットされない(最初の部分の更新が同じテーブルから読み込まれる)ときに、そのメッセージがキューにのみ存在すると予想されるにもかかわらず、データベースが更新されるのと同時に。後でテーブルをクエリすると、更新されたデータが期待どおりに存在します。これは、負荷が高く、ごくまれにしか発生しない場合に発生します。

だからここ

// code that processes message 1 
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions() { Timeout = TimeSpan.FromMinutes(30), IsolationLevel = IsolationLevel.ReadCommitted }) 
{ 
    MethodThatUpdatesTableX(); 
    MethodThatCreatesMessage2(); 
    scope.Complete(); 
}  

// message picked up from MSMQ and then (this runs in different thread): 
// code that process message 2 
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, new TransactionOptions() { Timeout = TimeSpan.FromMinutes(30), IsolationLevel = IsolationLevel.ReadCommitted }) 
{ 
    MethodThatReadsFromTableX(); // so here it seems that changes made in MethodThatUpdatesTableX is sometimes (though rarely) not read 
    // other stuff 
}  

我々のコードの

簡易版は、私の理解です:スコープがキューに公開を約束されているテーブルのXへの変更だけでなく、メッセージを配置されている

MethodThatReadsFromTableX()テーブルXIから読み取ると、変更がそこにあると予想されます(キューからメッセージを受け取ることができないため、最初のセッションが完了する前にセッションを作成しないでください)

私の期待は正しいですか?何が問題なの?

答えて

1

私はあなたに本当に、本当に短い答えを与えます。

あなたの分離レベルとしてSerializableを使用してください。これは、読者が作家によってブロックされることを保証する唯一の方法です。

残り...

SQLを使用すると、クラスタ化インデックスに順次挿入されていない限り、行レベルロックで非常に良いです。この場合、重複したキーエラーを挿入して処理することでパフォーマンスが向上します。

また、読み込みが汚い読者もシリアライズ可能な読者であることを確認する必要があります。そうしないと、データベーストランザクションがコミットされる前に公開メッセージが消費されてしまいます。私は大量生産システムでこれを見てきましたが、それは起こります(もちろん、RabbitMQではMSMQよりもRabbitMQの方がはるかに高速です)。

1

この問題に関する私の考えは次のとおりです。

分散トランザクションでは、通常2フェーズコミットが使用されます。第1フェーズでは、transacitonコーディネーターは誰もがコミットを準備するように頼みます。誰もが同意すれば、フェーズ2のコーディネーターは皆に変更をコミットするよう指示します。この段階でノードが変更をコミットした場合、ノードはそれ以上ロールバックされないことに注意してください。また、参加者A(たとえばSQL Server)と参加者B(MSMQ)の間には必然的に変更がコミットされることになることに注意してください。 MSMQが既に変更をコミットした場合、SQL Serverはまだ(既にコマンドされていますが)まだない可能性があります。

MSMQがトランザクションをコミットすると、作成したメッセージがプロセッサに配信されるのを防ぐことはできません。したがって、最初の「スコープ」ブロックを残す前でさえ、プロセッサが受信したメッセージの処理を開始し、SQLサーバーがまだに変更されている可能性があります。分散トランザクションでは、すべての参加者に何時かの変更をコミットすることができないため、このような動作を防ぐことはできません。

長いストーリー短く - 私はそれが意図したとおりに機能すると思うので、MSMQメッセージを処理するときに必要なデータが失われ、再試行ロジックを実装する準備が必要です。

関連する問題