0

昨日、ステージング<->プロダクションの役割を交換しようとしたときに、ひどい問題/経験がありました。

設定は次のとおりです。

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

交換時の問題:

私たちのステージングプロジェクトがオンラインになったとき、私たちのプロダクションワーカーの役割はエラーになり始めました。

ロールがキューメッセージを処理したいとき、それは「EntityAlreadyExists」エラーの一定の流れを与えました。これらのエラーのため、キューメッセージは削除されませんでした。これにより、キューメッセージがキューに戻され、処理などに戻されました。

これらのキューメッセージの内部を調べて、それらで何が起こるかを分析すると、実際には処理されたが削除されていないことがわかりました。

これらの誤ったメッセージを削除しても、問題は解決しませんでした。新たにキューメッセージも処理されませんでしたが、これらはまだ処理されておらず、テーブルストレージレコードも追加されていませんでした。これは非常に奇妙に聞こえます。

ステージングと本番環境の両方を削除し、本番環境に再度公開すると、すべてが正常に機能し始めました。

考えられる問題?

実際に何が起こったのかわかりません。

  • たぶん、両方の役割が同じメッセージを受け取り、1つは投稿を行い、もう1つはエラーになりましたか?
  • ... ???

可能な解決策)?

この「問題」を解決する方法について、いくつかのアイデアがあります。

  • ポイズンメッセージをシステムにフェイルオーバーさせますか?デキューカウントがXを超えたら、そのキューメッセージを削除するか、別の「poisonqueue」に配置する必要があります。
  • EntityAlreadyExistsエラーをキャッチし、そのキューメッセージを削除するか、別のキューに入れます。
  • ... ????

複数の役割

複数の役割を設定するときに同じ問題が発生すると思いますか?

どうもありがとう。

2012年2月24日編集-追加情報

  • 実際にGetMessage()を使用します
  • キュー内のすべてのアイテムは一意であり、テーブルストレージに一意のメッセージを生成します。プロセスに関するもう少しの情報:ユーザーが何かを投稿し、特定の他のユーザーに配布する必要があります。そのユーザーから生成されたメッセージには、一意のID(GUID)があります。このメッセージはキューに投稿され、ワー​​カーロールによって取得されます。メッセージは他のいくつかのテーブル(partitionkey-> UserId、rowkey->ティック単位のタイムスタンプと一意のメッセージID)に分散されます。したがって、通常の状況で同じメッセージが投稿される可能性はほとんどありません。
  • 一部のメッセージは10〜20個のテーブルに分散される可能性があるため、非表示のタイムアウトは論理的な説明になる可能性があります。これは、バッチオプションなしで10-20挿入を意味します。この不可視タイムアウトを設定または拡張できますか?
  • 例外のためにキューメッセージを削除しないことも、ポイズンメッセージフェイルオーバーをまだ実装していないため、説明になる可能性があります;)。
4

5 に答える 5

2

ステージングと本番の問題に関係なく、ポイズンメッセージを処理するメカニズムを持つことが重要です。Azureキューに抽象化レイヤーを実装しました。これは、メッセージが構成可能な回数処理されると、メッセージをポイズンキューに自動的に移動します。

于 2012-02-23T17:57:50.003 に答える
1

ワーカーロールが実際に何をしているのかわからないので、ここで推測しますが、ワーカーロールのインスタンスが2つ実行されていると、Azureテーブルに書き込もうとしているときに競合が発生しているようです。次のようなコードがあることが原因である可能性があります。

var queueMessage = GetNextMessageFromQueue();    

Foo myFoo = GetFooFromTableStorage(queueMessage.FooId);

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

    AddFooToTableStorage(myFoo);
}

DeleteMessageFromQueue(queueMessage);

同じキューに2つの隣接するメッセージがFooIdある場合、両方のインスタンスが存在するかどうかを確認しFoo、見つからずに作成しようとする可能性が非常に高くなります。アイテムを保存しようとする最後のインスタンスはどれでも、「エンティティはすでに存在します」というエラーが発生します。エラーが発生したため、コードの削除メッセージ部分に到達することはなく、一定期間後にキューに戻って表示されるようになります。

他の人が言っているように、毒メッセージを扱うことは本当に良い考えです。

更新27/02 後続のメッセージではない場合(パーティション/行キースキームに基づいて、それはありそうもないと思います)、次の賭けは、可視性タイムアウト後にキューに戻って表示される同じメッセージです。デフォルトでは、.GetMessage()を使用している場合、タイムアウトは30秒です。オーバーロードがあり、その時間枠の長さを指定できます。メッセージの処理中にタイムアウトを更新できる.UpdateMessage()関数もあります。たとえば、最初の可視性を1分に設定し、50秒後もメッセージを処理している場合は、さらに1分間延長します。

于 2012-02-24T02:00:15.870 に答える
1

考えられる原因はいくつかあります。

キューメッセージをどのように読んでいますか?ピークメッセージを実行している場合、メッセージが削除される前に、メッセージは引き続き表示され、別のロールインスタンス(またはステージング環境)によってピックアップされます。Get Messageを使用していることを確認して、メッセージが削除されるまでメッセージが表示されないようにします。

メッセージの作業を行った後、メッセージを削除する前に、最初の役割がクラッシュした可能性はありますか?これにより、メッセージが再び表示され、別のロールインスタンスによって取得されます。その時点で、メッセージはポイズンメッセージになり、インスタンスが絶えずクラッシュします。

この問題は、ほぼ確実にステージングと本番環境とは関係ありませんが、同じキューから複数のインスタンスを読み取っていることが原因である可能性があります。2つのインスタンスを指定するか、同じコードを2つの異なる本番サービスにデプロイするか、2つのインスタンスを使用して開発マシン(Azureストレージをポイントしている)でコードをローカルで実行することで、同じ問題を再現できる可能性があります。

一般に、ポイズンメッセージを処理する必要があるため、とにかくそのロジックを実装する必要がありますが、最初にこの問題の根本原因を突き止めることをお勧めします。そうしないと、後でさらに多くの問題が発生します。

于 2012-02-23T21:29:40.027 に答える
1

キューを使用する場合は、べき等性を念頭に置いてコーディングし、「EntityAlreadyExists」を実行可能な応答として期待して処理する必要があります。

他の人が示唆しているように、原因は

  • 同じ識別子を持つキュー内の複数のメッセージ。
  • メッセージをのぞき見していて、キューからメッセージを読み取っていないため、メッセージが非表示になっていない。
  • メッセージを削除する前に例外がスローされたため、メッセージを削除しません。
  • メッセージの処理に時間がかかりすぎて、メッセージを削除できず(非表示がタイムアウトしたため)、再び表示されます

コードを見ずに、発生しているのは3または4オ​​プションのいずれかであると推測しています。

コードレビューで問題を検出できない場合は、理解を深めるために、時間ベースのロギングとtry/catchラッパーを追加することを検討してください。

マルチロール環境でキューを効果的に使用するには、わずかに異なる考え方が必要であり、このような問題に早期に遭遇することは、実際には偽装の祝福です。

2/24追加

明確にするために、不可視性のタイムアウトを変更することは、このタイプの問題に対する一般的な解決策ではありません。また、この機能はREST APIで使用できますが、キュークライアントでは使用できない場合があることに注意してください。

他のオプションには、処理時間を短縮するために非同期でテーブルストレージに書き込むことが含まれますが、これもストップギャップ対策であり、キューを操作する基本的なパラダイムに実際には対応していません。

したがって、収益はべき等である必要があります。コードで機能する場合は、テーブルストレージのアップサート(更新または挿入)機能を使用して、「EntitiyAlreadyExists」エラーが発生しないようにすることができます。Azureテーブルストレージに新しいエンティティを挿入するだけの場合、アップサートは最小限のコード変更で問題を解決するはずです。

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

于 2012-02-24T05:35:58.477 に答える
1

明らかに、二重メッセージの処理に問題があります。IDが一意であるという事実は、次のような場合にメッセージが2回処理されないことを意味するわけではありません。

  1. 役割が終了し、作業が部分的に終了したため、メッセージはキューで処理するために再表示されます
  2. ロールが予期せずクラッシュしたため、メッセージはキューに戻ってしまいます
  3. FCが移行して役割を移動し、この状況を処理するコードがないため、メッセージはキューに戻されます

いずれの場合も、メッセージが再表示されるという事実を処理するコードが必要です。1つの方法は、DequeueCountプロパティを使用して、メッセージがキューから削除され、処理のために受信された回数を確認することです。メッセージの部分的な処理を処理するコードがあることを確認してください。

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

于 2012-03-26T01:14:19.540 に答える