web-dev-qa-db-ja.com

重要なメッセージをDLQキューからプルしてリレーショナルデータベースに保存し、分析して後で送信します。それは良い考えですか?

私のプロジェクトには外部システムとの統合があります。このシステムにいくつかの重要な情報を送信する必要があります。このために、この外部システムに接続するマイクロサービスを作成します。このマイクロサービスは専用のキューで内部システムから非同期メッセージを受信し、マイクロサービスはメッセージを読み取って外部システムに送信しようとします。とても簡単です。

私の疑問を説明する前に、皆さんに状況を説明します。

環境

この外部システムが信頼できるかどうかはわかりません。場合によっては、外部システムがオフになり、これから回復する方法が必要になります。したがって、再試行メカニズムを実装します。ただし、この外部システムが長時間オフになり、サポートチームと話し合うまで有効なメッセージの一部が拒否されることも考えられます。したがって、この拒否されたメッセージを受信するために、耐久性のあるDead Letter Queueも作成します。

最悪のシナリオでは、拒否された原因を分析するために、DLQキューに大量のメッセージが表示されます。したがって、私のチームは、DLQキューからメッセージをプルし、Jsonとしてデータベースに永続化するという考えを持っています。これは、メッセージを編集するために想像するためです。

質問

そして私の質問は、この最後の段落についてです。データベースにメッセージを保存します。良いアイデアかどうかはわかりませんが、データベースのキューから永続的な機能を複製しているだけのようです。

この考えは、データベース上のメッセージが分析しやすくなることから生まれました(たぶん必要です)、それらを編集します(たぶんRabbitMQ管理とメッセージの1つの間違いがなくなったため、おそらく必要ない)必要があり、メッセージを操作するためのより信頼できる方法があります。また、データベースからこのメッセージを読み取り、メインキューに再送信するために、何らかのcronジョブが必要になります。

ご覧のとおり、maybeと多くの追加作業(データベース、テーブル、cronジョブなど)があり、私はソリューションに本当に快適です。もちろん、メッセージをリレーショナルデータベースで分析および編集できればより安全ですが、将来この機能を使用するかどうかはわかりません。

チームで分析してメインキューに再送信できる拒否されたメッセージにRabbitMQを使用することについて調査しましたが、これは一般的なシナリオではありません。

1
Dherik

対処している問題の適切な用語は、「有害メッセージ処理」です。デッドレターキューは通常、メッセージングシステムで配信不能メッセージ用に使用されます。ポイズンメッセージは、クライアントアプリケーションが正常に処理できないメッセージです。 「有害メッセージキュー」は、メッセージが無期限に読み取られてロールバックされるのを防ぐために、これらのメッセージを受信するように構成されたキューです。これは、1つの不正な要求によってメッセージがバックアップされ、キューの深さを超えて上流の障害が発生するのを防ぐための良い方法です。

ダウンストリームアプリケーションがどこでオフラインになっているかが気になる特定のケースでは、1つの簡単な解決策は、キュー上のメッセージの処理を停止することです。これにはいくつかの問題があります。主なものは、大量のメッセージが入ってくると、キューがいっぱいになる可能性があるということです。もう1つの潜在的な問題は、そのキューが永続的でない場合、大量のメッセージがキューに置かれていると、データが失われるリスクがあることです。

メッセージングソリューションでの私の経験から、データの損失を防ぐためにキューに依存しないでください。ベンダーが「保証された配信」について何を主張していても、そのようなシステムをリーク防止にすることには、多くの落とし穴と課題があります。何かが確実に到着するようにする必要がある場合は、失われた場合にメッセージを再生成できるように十分な情報を保持する永続的なストアが必要です。多くの場合、これはデータベースにあります。これは提案したものと似ていますが、メッセージがキューから読み取られているときにメッセージをDBにプッシュするのではなく、発信元でDBに留まります。さらに、そのストア内の各レコードの最終状態を(少なくとも)記録する元帳タイプのアプローチをお勧めします。データを消去する必要がある場合は、後で一括で消去できます。

これを行うと、キューは関係ないように見えるかもしれませんが、そうではありません。キューは、分散システムでメッセージを移動および処理し、競合を回避するための優れた方法です。キューでDB元帳を使用することにより、両方の長所を活用できます。

1
JimmyJames

これについてのあなたの懸念を理解しましたが、そうです、キューシステムからデッドメッセージを抽出する必要があります。

これを言った私の唯一の理由はこの文章です:

サポートチームと話し合うまで、有効なメッセージを拒否することもできます

デッドレターキューは、例外やコンポーネントの内訳の処理に最適ですが、問題を修正した後、それらのメッセージを再実行すると、メッセージが正しくフローバックされることが期待されます。

しかし、手動での介入と、場合によってはプロセスの一部として個々のメッセージを編集する必要があるようです。つまり、チームが定期的にこのデータを確認し、その有効性について第三者と議論し、場合によっては一部のデータを変更して再送信することが予想される動作です。

実際にこの要件がある場合、そのプロセスを処理するアプリケーションにメッセージをデシリアライズする必要があると私は言うでしょう。おそらく永続化レイヤーと適切なUIを含みます。 jsonを編集し、手動でキュー設定をいじくる人に任せることはできません。

したがって、jsonを使用したデータベースの提案された解決策は、DLQとほとんど変わらないことをはるかに強調します。

おそらくあなたは彼らに「これらが本当に私たちが期待することであり、それがreal要件であるなら、見てください。それから私たちは完全な解決策をとるべきです。キューよりも快適で、データベースですべてを行う必要があります。

1
Ewan

私たちがどのような決断をするかについて興味がある人のために:

  • DLQのアイデアは拒否されました。あまりにも複雑すぎて、実際の利益はありません。
  • メインキューからメッセージを読み取り、before信頼できない外部サービスと通信し、ステータスSENDINGのテーブルにメッセージを保存します。メッセージ全体をJson形式で保存するための特定の列と特定の列(理由は後で説明します)。
  • 信頼できない外部システムとの統合が成功した場合、ステータスをSENDINGからSUCCESSに変更します。
  • 統合で何らかの問題が発生した場合は、例外を取得し、最初のテーブルにリンクされている2番目のテーブルにエラーを保存して、ステータスをSENDINGからERRORに変更します。
  • その後、何らかのジョブを使用して統合を再度トリガーするか、バックオフィスユーザーにこの決定を行うかを選択できます。パフォーマンスの問題などが発生しないようにするために、ユーザー/ジョブがERRORメッセージを再度送信しようとしたときに、Json列を読み取り、元のJsonを元のJavaクラスに解析します(私たちはSpringを使用しています)そして同じプロセスに従うためにメインキューに再度送信します。

それは非常にうまく機能します。これと同じ戦略を複数の統合に適用しており、不満はありません。

0
Dherik