2012-02-23 8 views
0

プロダクションロール<をスワップしようとすると、昨日恐ろしい問題や経験がありました。Windows Azureのステージング<-->プロダクションがテーブルストレージの競合とエラーの原因となる

私たちは、キューからメッセージを拾っworkerroleを持っている:

は、ここに私たちの設定です。これらのメッセージはロールで処理されます。 (テーブルストレージの挿入、dbの選択など)。これは、彼が作る必要があるテーブルストレージポストの数に応じて、キューメッセージごとに1〜3秒かかることがあります。彼はすべてが終わったらメッセージを削除します。

問題スワップ:私たちのステージングプロジェクトは、オンライン当社の生産workerroleを行ってきました

はerroringを開始しました。

ロールがキューメッセージを処理したいとき、定数ストリームに 'EntityAlreadyExists'というエラーが発生しました。これらのエラーのため、キューメッセージは削除されませんでした。これらのキューのメッセージ内を調べ、それらと起こっなるのか分析する場合これは、我々は、彼らが実際に処理が、削除されませんでした見た....キューメッセージがバックキューでバック処理にというように置くことが

を引き起こしました。

これらの障害メッセージを削除するときに問題は解決しませんでした。新しくキューメッセージは処理されませんでしたが、まだ処理されず、テーブルストレージレコードが追加されませんでしたが、これは非常に奇妙なものです。再び生産にステージングし、産・出版の両方を削除する場合

は、すべてがうまく動作し始めました。

可能性のある問題(s)は?

我々はlitle 2に実際に何が起こったのか見当がつかない。

  • 両方の役割が同じメッセージを受け取り、1つが投稿を行い、1つがエラーになることはありますか?
  • ... ???

解決策はありますか?

私たちはこの「問題」を解決する方法についていくつかのアイデアを持っているの。

  • 有害メッセージを作成しますが、システム上の失敗しますか?デキューカウントがXを超えると、そのキューメッセージを削除するか、別の 'poisonqueue'に配置するだけです。
  • EntityAlreadyExistsエラーをキャッチして、そのキューメッセージを削除するか、別のキューに格納するだけです。
  • ... ????

複数の役割

私は複数の役割を置くときに我々は同じ問題を抱えているだろうと仮定?

多くのありがとうございます。

EDIT 24/02/2012 - 追加情報が

  • 私たちが実際に値getMessage()を使用し
  • キュー内のすべての項目は一意であり、テーブルストレージでユニークなメッセージを生成します。プロセスに関する情報はほとんどありません。ユーザーは何かを投稿し、他の特定のユーザーに配布する必要があります。そのユーザーから生成されるメッセージには、一意のId(guid)が付けられます。このメッセージはキューにポストされ、ワー​​カー・ロールによって選択されます。メッセージはいくつかの他のテーブルに分配されます(パーティションキー - > UserId、rowkey - >タイムスタンプのティックで&ユニークなメッセージID)。 うちいくつかのメッセージがこれはバッチオプションを使用せずに10〜20のインサートを意味します。10-20テーブルを好きに配布される可能性があるため。あなたが設定またはこの不可視期間を拡大アウト?
  • が削除できないのは論理的な説明することができキューメッセージは例外のためとなります。も同様です。
+0

最新のキュー実装では、可視性のタイムアウトを変更できます。 http://msdn.microsoft.com/en-us/library/windowsazure/hh452234.aspx – hocho

答えて

1

あなたは明らかにダブルメッセージを処理することに誤りがあります。

  1. 役割は死ぬし、部分的に完成した作品で、その中にメッセージが処理のために再表示されます:あなたのIDが一意であるという事実は、次のようにメッセージがいくつかの場面で2回処理されないことを意味するものではありませんキュー
  2. 役割クラッシュ予期しない、メッセージがバックキュー
  3. 自分の役割を移動する移行FCで終わると、あなたはこのような状況を処理するコードを持っていないので、メッセージはキューに戻って終わるよう

すべてのケースで、その事実を処理するコードが必要ですメッセージが再び表示されます。 1つの方法は、DequeueCountプロパティを使用して、メッセージがキューから削除され、処理のために受信された回数をチェックすることです。メッセージの処理の一部を処理するコードがあることを確認してください。

スワッピング中に起こったことは、プロダクション環境がステージングとステージングがプロダクションになったときに、両方が同じメッセージを受信しようとしていたため、それらのメッセージと基本的に競合していましたこれはとにかく動作する既知のパターンなので、処理のために受け取ったすべてのメッセージを処理して終了していない古いプロダクション(ステージング)を終了したときにキューに戻ってしまい、新しいプロダクション環境が再び処理のメッセージを選択しました。このシナリオを処理するコードロジックがなく、メッセージが部分的に処理されていたため、テーブル内のレコードがいくつか存在し、気付いた動作が発生し始めました。

2

ステージングとプロダクションの問題にかかわらず、ポイズンメッセージを処理するメカニズムが重要です。 Azureキュー上の抽象レイヤーを実装しました。この抽象レイヤーは、設定可能な量の処理を試みると自動的にポイズンキューにメッセージを移動します。

1

いくつか原因が考えられます。

キューメッセージをどのように読んでいますか? Peek Messageを実行している場合、メッセージは、メッセージが削除される前に別のロールインスタンス(またはステージング環境)によって選択されたまま表示されます。あなたは、メッセージが削除されるまでメッセージが見えないように、メッセージの取得を使用していることを確認する必要があります。

メッセージの処理後、メッセージを削除する前に、最初のロールがクラッシュする可能性はありますか?これにより、メッセージが再度表示され、別のロールインスタンスによってピックアップされます。その時点で、メッセージはあなたのインスタンスが絶えずクラッシュするような毒メッセージになります。

この問題は、ステージングとプロダクションとはまったく関係がありませんが、同じキューから複数のインスタンスを読み取っている可能性が最も高いです。 2つのインスタンスを指定するか、2つの異なるプロダクションサービスに同じコードをデプロイするか、2つのインスタンスを使用してdevマシン(Azureストレージを指しています)上でローカルにコードを実行することによって、同じ問題を再現できます。

一般に、毒のメッセージを処理する必要があるため、その論理を実装する必要がありますが、まずはこの問題の根本原因を調べることをお勧めします。そうでなければ、後でさらに多くの問題に遭遇します。 。

+0

ありがとうございます。私はより多くの情報で私のポストを編集しました:) –

1
ワーカーの役割は、実際に私はここに推測を取ってやっていることを知らず

、それはあなたがAzureのテーブルへの書き込みしようとしているときは、競合を取得している実行しているWorkerロールのインスタンスを2つ持っているときのように聞こえます。あなたは同じFooIdと、キュー内の隣接する二つのメッセージを持っている場合

var queueMessage = GetNextMessageFromQueue();  

Foo myFoo = GetFooFromTableStorage(queueMessage.FooId); 

if (myFoo == null) 
{ 
    myFoo = new Foo { 
         PartitionKey = queueMessage.FooId 
        }; 

    AddFooToTableStorage(myFoo); 
} 

DeleteMessageFromQueue(queueMessage); 

が、あなたがインスタンスの両方で終わるだろうということは非常に可能性があります:あなたがこのようになりますコードを持っているためである可能性が高いですFooが存在するかどうかを確認し、見つからない場合は作成します。どのインスタンスがアイテムを最後に試して保存しようとしても、「エンティティは既に存在します」というエラーが発生します。エラーが発生したため、コードの削除メッセージ部分には決して行きません。したがって、一定期間後にキューに戻って表示されます。他の人が言ったように

は、有害メッセージを扱うことは本当に良いアイデアです。

更新27/02: それは(私はそれがそうだと言うでしょう、あなたのパーティション/行鍵方式に基づいて)その後のメッセージではない場合は、私の次の賭けは、それが後にキューに戻って表示される同じメッセージだだろう可視性タイムアウト。デフォルトでは、.GetMessage()を使用している場合、タイムアウトは30秒です。これにはoverloadがあり、その時間枠の長さを指定することができます。 .UpdateMessage() functionもあり、メッセージの処理中にそのタイムアウトを更新することができます。たとえば、最初の可視性を1分に設定してから、50秒後にメッセージを処理している場合は、それをもう1分間延長します。あなたが実行可能な応答として「EntityAlreadyExists」を念頭に置いて冪等でコーディングすると期待して処理する必要がキューに

+0

メッセージは100%ユニークです:)私は少し詳細については私のポストを更新しました。 –

1

。他の人が提案してきたように

、原因は同じ識別子を持つキューにある

  • 複数のメッセージである可能性があります。
  • メッセージが覗き込まれていて、それをキューから読み取っていないため、メッセージが見えなくなりません。
  • メッセージを削除する前に例外がスローされたため、メッセージを削除しません。それを削除することはできませんので(不可視がタイムアウトしたため)、私はそれがどちらかである3または4の選択肢であることを推測していたコードを見ずに再び

表示されます

  • は、メッセージの処理に時間がかかりすぎて発生します。あなたがコードレビューの問題を検出できない場合

    は、あなたが時間ベースのログを追加することを検討し、より良い理解を得るために/キャッチラッパーをしようとします。

    使用してキュー効果的に、マルチロール環境では、わずかに異なる考え方を必要とし、早期にそのような問題に実行すると、実際には不幸中の幸いです。ただ、不可視期間を変更し、明確にするために2月24日

    を別記

    は、この種の問題に対する一般的なソリューションではありません。また、この機能はREST APIで使用可能ですが、キュークライアントでは使用できない場合があります。

    その他のオプションは、あなたの処理時間をスピードアップするために、非同期的にテーブルストレージへの書き込みを伴うが、やはりこれは本当にキューでの作業の基本的なパラダイムに対応していませんストップギャップ対策です。

    だから、一番下の行は、冪等することです。あなたのコードでうまくいけば、 'EntitiyAlreadyExists'エラーを避けるために、テーブルストレージのupsert(更新または挿入)機能を使ってみることができます。新しいエンティティを空白のテーブルストレージに挿入するだけであれば、upsertは最小限のコード変更で問題を解決するはずです。

    更新を行っている場合、それはすべて一緒に別のボールゲームです。 1つのパターンは、同一のパーティションキーを持つ同じテーブル内のダミー挿入と更新をペアにして、以前に更新が発生した場合にエラーになり、更新をスキップすることです。後でメッセージが削除された後、ダミー挿入を削除することができます。しかし、このすべてが複雑さを増すため、製品のアーキテクチャを再検討するほうがずっと優れています。たとえば、本当に多くのテーブルに挿入/更新する必要がありますか?

  • +0

    あなたの3つと4つのオプションが実際に見える '見た目'。私はもう少し詳しい情報を投稿しました。 –

    関連する問題