RocketMQ実戦まとめ|メッセージキュー蓄積問題のトラブルシューティングを記録

1. 背景

写真

この問題に関係するシステム リンクは上の図に示されており、各システムの基本的な役割は次のとおりです。

  • プロキシ: リクエストのプロキシ サービスを提供します。下流システムに送信されるさまざまなリクエストを統合エージェントにより、上流システムが下流サービスの使用の違いを認識する必要がなく、同時に電流制限や迂回などの洗練されたサービス機能を提供します。
  • Latu SDK: 各ストレージ プラットフォームに統合されたイメージ ダウンロード機能を提供します。通常、画像アルゴリズム モデルと一緒に配置されます。
  • 推定エンジン: モデル推論サービスを提供します。さまざまな機械学習および深層学習アルゴリズム モデルのエンジニアリング展開をサポートします。

2. トラブルシューティング

注: この記事で使用されているメッセージ キューは内部的には MetaQ と呼ばれており、外部のオープン ソース バージョンは RocketMQ (以下では「MQ」と呼びます) です。

2.1 問題の説明

ある朝、Proxy システムの入口 MQ が蓄積したことを示すアラーム通知を受け取りました。コンソールを開くと、500 台のプロキシ マシンのうち、1 台のマシンに深刻な蓄積が見られ、残りのマシンは正常に動作していることがわかります。

写真

2.2 文の根本原因

早速本題に入り、問題の根本原因について直接話しましょう (詳細なトラブルシューティング プロセスについては、次のコンテンツを参照してください)。

  • 個々のマシンの蓄積: マシンにはスタックしている消費スレッドがあります。残りのスレッドは正常に消費しますが、MQ メカニズムは消費位置が進めないと判断します。
  • HTTP ダウンロードが停止する: 使用されている HttpClient のバージョンにはバグがあり、特定の状況下ではタイムアウトが有効にならないため、スレッドが常に停止する可能性があります。

2.3 トラブルシューティングのプロセス

1. マシンの消費速度が遅すぎませんか?

最初の反応は、このマシンの消費が遅すぎるということです。同じ量の情報は他のマシンによってすぐに消化されますが、消費が遅いため蓄積され続けます。ただし、MQ コンソールで詳細に比較した結果、このマシンのビジネス処理時間と消費 TPS は他のマシンと同様であり、異なるマシンの仕様も同じであることがわかります。

写真

次に、Arthas によって描かれたフレーム図を観察してください。右側の 2 つの細い炎は、システムのビジネス ロジックです (RPC コール スタックが深いため、炎が高くなるほど)。この図から、フレーム グラフには明らかな「フラットトップ効果」がなく、フレームの幅が比較的狭いことがわかります。これは、マシンの実行時に明らかな時間のかかるスタック ポイントがないことも示しています。ビジネス ロジック: ビジネス処理の遅さが原因でマシンが蓄積されていないことを証明します。

写真

2. システムインジケーターは正常ですか?

マシンにログインすると、CPU、MEM、および LOAD がすべて正常で、通常のマシンと同様であり、明白な手がかりが見つからないことがわかります。

写真

そして、マシンには明らかなフル GC がありません。

写真

3. 電流制限が原因ですか?

ヒント: プロキシには、リクエストをプロキシする際のフロー制限メカニズムがあり、制限を超えるトラフィックはブロック待機をトリガーし、それによってダウンストリーム同期サービスを保護します。

したがって、現在システム トラフィックが非常に大きく、ダウンストリーム サービスが耐えられる制限を超えている場合、超過リクエストによって RateLimiter フロー制限がトリガーされ、ブロックされます。その結果、多数の MQ コンシューマ スレッドがブロックされるため、プロキシ システムの全体的なメッセージ消費速度が低下し、最終的にはエントリ トピックが蓄積されます。

写真

ただし、ログを見ても、マシンの監視を見ても、電流制限によるブロック現象は深刻ではなく、比較的スムーズに行われています。

写真

第 2 に、それが本当に今日のシステムの大量の入力トラフィックによって引き起こされている場合、すべてのプロキシ マシン (MQ コンシューマ) には同様のレベルの蓄積があるはずです。他の 499 台のマシンは正常ですが、すべてを同じマシンにスタックすることはできません。したがって、システムの入口流量が大きすぎる可能性を確認してください。

4. MQ データのスキュー?

500 台のプロキシ マシンが受信 MQ でメッセージを均等に分散すると予想されます。データ分散に偏りがあり、その結果、このマシンのメッセージが多すぎて、他のマシンのメッセージが少なくなる可能性はありますか?

プロキシの上流システムのコードを確認してください。システムはプロキシにメッセージを送信するときにカスタム シャッフルを実行しないため、MQ のデフォルトの selectOneMessageQueue 戦略が使用されます。そして、この戦略は、インデックス % queue_size に基づいて選択されたキューに現在のメッセージを送信します。インデックスのロジックをさらに詳しく見てみると、初期化時に乱数から始まり、アクセスされるたびに +1 ずつ増加することがわかります。

写真

上記の 2 つの点を組み合わせると、次のような効果が得られます。各キューにメッセージを左から右に均等に分散し、% による自動循環を実現します。

写真

要約すると、MQ のデフォルトのシャッフル戦略は、メッセージを各キューに均等に分割することです。したがって、MQ によって送信されたメッセージ データの偏りが原因でプロキシ マシンに蓄積される可能性を排除できます。

5、CPUスティール?

ヒント: CPU スティールは、仮想マシンで実行されているプロセスがホスト マシン上の他のプロセス/仮想マシンによって占有されている CPU 時間の割合を示します。CPU スティールの値が高いということは、通常、仮想マシンのプロセスのパフォーマンスが低下していることを意味します。

たとえば、マシンの仕様自体には 4C と記載されていますが、実際には盗難後に使用できるのは 2C だけです。反映された結果は、単一リクエストの RT は大きく変化しません (異なる C の差は大きくありません) が、C の量が減少するため、このマシンの全体的なスループットが小さくなり、消費能力が弱くなり、蓄積につながります。

ただし、調査の結果、st は正常であることが判明し、この可能性は除外されます。

写真

6. 手がかりを見つける: MQ の消費場所は変わっていません。

一通り見て回ったところ異常箇所は見当たりませんでしたが、問題の現象はMQの蓄積なので、ミドルウェアのログを確認すれば手がかりが見つかるのではないかと考えました。案の定、スタックしたマシンの queueId の方向検索により、このキューの消費ポイントが長い間進められておらず、特定の位置でスタックしていることが判明しました。

写真

ヒント: MQ がメッセージをプルするメカニズムでは、プルされたメッセージはまずメモリ内の容量 1000 のキャッシュに保存され、次にメモリ内のメッセージがコンシューマ スレッドによって消費されます。キャッシュがいっぱいになると、キューからキャッシュが取得されなくなります。

写真

このことから、プロキシの消費が停止するため、または消費が非常に遅いため、ローカル キャッシュが常にいっぱいになり、MQ がキューからのメッセージの取得を停止するため、オフセットは変更されないのではないかと考えます。

ただし、上で述べたように、MQ コンソール、システム監視インジケーター、およびマシン ログに関係なく、マシンは正常であり、他のマシンと何の違いもありません。では、なぜ機械の消費点が動かず、蓄積がますます深刻になるのでしょうか。

7. 根本原因を見つける: コンシューマ スレッドがスタックしている

ヒント: ローカル キャッシュ内のメッセージの場合、MQ は複数のスレッド (スレッドの数はユーザーが指定します) を開いて、消費をプルおよびキャンセルします。また、メッセージが失われないようにするために、オフセットには最前面のメッセージのみが記録されます。

まずメカニズムがしっかりしている。At Least Once セマンティクスでは、メッセージを複数回使用することは許可されますが、見逃すことは許可されないためです。現在、2 つのメッセージを同時にプルする 2 つのスレッドがあり、後者のメッセージが最初に実行されるとします。前のメッセージの実行が異常である可能性があるため、後者のオフセットを直接使用してオフセットを更新することはできません。そうしないと、消費失敗のメッセージが取得されません。したがって、消費ポイント オフセットの意味は、この位置以前のすべてのメッセージが正しく消費されたということです (Flink のウォーターマーク メカニズムにある程度似ています)。

上記のメカニズムに従って、この質問に戻りますが、このプロキシ マシンの多くの MQ コンシューマ スレッドのいずれかがスタックした場合、キュー全体の消費位置は常にスタックしたメッセージに対応するオフセットに留まります。現時点では、他のスレッドは通常どおり消費を続けていますが、オフセットを前方に進めることはできません。一方、アップストリームは引き続きキューにメッセージを送信しているため、メッセージは送受信のみ可能であり、蓄積量 = 最新の受信メッセージのオフセット - 消費サイトのオフセットが増加するだけです。コンソール上の蓄積に反映されます。

この分析に基づいて、jstack を通じてすべての MQ コンシューマー スレッドのステータスをチェックすると、確かに 251 番のスレッドが常に実行可能な状態であることがわかります。

写真

コンシューマ スレッドがスタックしているのではないかと疑う理由があります。プロキシ システムのビジネス シナリオでは、ほとんどの時間はディープ ラーニング モデルを同期的に呼び出す RPC に費やされるため (高速で数百ミリ秒、低速で数秒)、スレッドは同期呼び出しが返されるのを待つ必要があります。ほとんどの場合は待機状態です。ただし、ここのスレッド 251 は常に実行可能であるため、問題があるはずです。

さらに詳細を出力して、スレッドがスタックしている特定のコードの場所を見つけます。

写真

ここで、getImageDetail メソッドは、深層学習モデルが予測できるように、内部的に HTTP 経由で画像をダウンロードします。次に、ビジネスログを検索したところ、このスレッドのログが見つからないことがわかりました。昨夜 10 時に停止したため、このスレッドは新しいログを生成しません。マシンのログがロールされてクリーンアップされると、すべてのログにこのスレッドの内容が含まれるようになります。

写真

これまでのところ、プロキシ システム内の個々のマシンに MQ が蓄積されるという深刻な問題の根本原因が判明しました。HTTP 経由で画像をダウンロードするときにこのマシンのコンシューマ スレッドがスタックし、キュー全体の消費が先に進まなくなりました。 、継続的に蓄積されます。

8. HTTP がスタックし続けるのはなぜですか?

これまでのところ、蓄積の根本原因は特定されており、試した結果、アプリケーションを再起動するか、短期的にはオフラインにすることで一時的に解決できます。しかし、最近では同じ問題が数日おきに時々現れるため、長期的には常に隠れた危険が存在します。この問題を根本的に解決するには、HTTP が滞る根本原因を徹底的に調査する必要があります。

数回のスクワットの後、スレッドがスタックする原因となるいくつかの画像 URL を取得しました。これらはどれも内部画像アドレスではなく、開くことができず、jpg 形式で終わっていないことが判明しました。

https://ju1.vmhealthy.cn
https://978.vmhealthy.cn
https://xiong.bhjgkjhhb.shop

しかし問題は、開けないような極端な URL を入力したとしても、HttpClient に 5 秒のタイムアウトを設定しているため、最大 5 秒間は停止することになります。 10時間以上立ち往生していますか?

ヒント: HTTP は、データ送信の前に接続を確立する必要があります。これは 2 つのタイムアウトに対応します: 1. 接続タイムアウト (接続を確立する段階)、2. ソケット タイムアウト (データ送信中のタイムアウト)。

写真

検査の結果、現在のコードではソケット タイムアウトのみが設定されており、接続タイムアウトは設定されていないため、上記のリクエストは前の接続段階で直接スタックしているのではないかと思われます。また、接続タイムアウトが設定されていないため、リクエストは行き詰まった?ただし、コードを変更してこれらのアドレスを再度要求しようとすると、依然としてスタックするため、さらなる調査が必要です。

9. HTTP スタックの根本原因を見つける

ヒント: 根本原因を見つけてください。HttpClient の特定のバージョンでは、SSL 接続に基づくリクエストにバグがあります。実際、最初に接続を確立しようとし、次にタイムアウト期間を設定しようとし、順序が逆になります。したがって、接続がスタックした場合、タイムアウトが設定されていないため、この HTTP リクエストは常にスタックすることになります。

写真

上記の詰まった URL を振り返ってみると、例外なくすべて https で始まります。事件は解決しましたが、プロジェクトで使用されている HttpClient にバグがあることが判明しました。HttpClientをバージョンアップしたところ、事前に発行していた構築テストリクエストが再発行され、スレッドの滞りがなくなり、全てオンライン環境に移行しましたが、最近多発していた少数マシン滞留問題は解消されました。再び発生することはありませんでした。

これまで紆余曲折を経て、ようやくこの問題は完全に解決されました。

2.4 全体的なレビュー

最外部の Proxy に個々のマシンが集積している様子から、根本原因が見つかるまで内部調査で多くの重要なノードを通過しました。現在、すべての問題は完全に調査されており、神の視点から見ると、内部から外部に至る完全な因果関係は次のとおりです。

–> プロキシ システムは HttpClient に基づいて画像をダウンロードし、推定のために画像クラス モデルを呼び出します。

–> 使用している HttpClient のバージョンにバグがあり、https アドレスにアクセスするとタイムアウトが発生しません

–> プロキシ システムはたまたま少数の https アドレスに遭遇し、たまたまスタックしたため (確率の低いイベント)、タイムアウトが有効にならないため常にスタックします。

–> MQ の At Least Once メカニズムに基づいて、消費ポイントは常にスタックメッセージに対応するオフセットに留まります (ただし、残りのスレッドは通常どおり消費しています)。

–> 上流システムは依然として Proxy にメッセージを継続的に送信しているため、メッセージは送受信しかできず、蓄積が悪化しています

–> 蓄積が特定のしきい値を超えると、監視アラームがトリガーされ、ユーザーはそれに気づきます

3. まとめ

この問題のトラブルシューティング プロセスは少し複雑ですが、多くの一般的な方法論や教訓も学ぶことができます。これらをこのセクションで要約します。

  • **トラブルシューティング ツールを上手に活用する: **jstack、Arthas、jprofile などの優れたツールの使い方を学び、さまざまなシナリオで適切なツールを上手に活用して、異常な点を効率的に見つけて手がかりを見つけ、徐々に発見します。問題の根本原因。
  • **異常な感受性:**場合によっては、問題を発見するためのヒントが早い段階で実際に目の前に示されることがありますが、さまざまな理由 (最初に問題について多くの疑問があった、まだ発見されていない多くの干渉要因など) により、除外されるなど) 手がかりを発見するには、より多くの経験が必要です。
  • ** 広範な情報検索: ** イントラネット上の文書を検索し、関連する担当者に相談するだけでなく、外部の英語 Web サイトで直接の情報を確認する方法も習得する必要があります。
  • **困難なときの忍耐力:** 隠れた問題の中には、一度問題が現れてもすぐに見つけて解決できないことがよくあります。根本原因を見つけるには、前後に数回の調査が必要になる場合があります。
  • ** 基礎知識の補足: ** 初めに MQ のオフセットの仕組みを知っていれば、いくつかの問題はそれほど遠回りする必要はありません。今後さまざまなミドルウェアを使用する過程で、その基本原理についてさらに学ぶ必要があります。
  • **形而上学的な質問は禁止です:** コードや機械は人を騙しません。すべての「形而上学的な」質問の背後には、一連の厳密で合理的な原因があります。

参考:

  • HttpClient のバグ:https://issues.apache.org/jira/browse/HTTPCLIENT-1478
  • 接続タイムアウトとソケットタイムアウト:https://stackoverflow.com/questions/7360520/connectiontimeout-versus-sockettimeout

おすすめ

転載: blog.csdn.net/agonie201218/article/details/131783826