「分散トレースシステム」の原理を一挙解説!

「分散トレースシステム」の原理を一挙解説!

マイクロサービス アーキテクチャでは、リクエストを完了するには、多くの場合、複数のモジュール、複数のミドルウェア、および複数のマシンが連携して動作します。

[[343625]]

画像はPexelsより

この一連の呼び出し要求の中には、シリアルなものもあれば、パラレルなものもあります。では、このリクエストの背後でどのアプリケーション、モジュール、ノード、および呼び出しの順序が呼び出されるか、どのように判断するのでしょうか?各モジュールのパフォーマンスの問題をどのように特定しますか?この記事ではその答えを明らかにします。

この記事では、以下の点について説明します。

  • 分散追跡システムの原理と機能
  • スカイウォーキングの原理とアーキテクチャ設計
  • 分散コールチェーンに関する当社の実践

分散追跡システムの原理と機能

インターフェースのパフォーマンスを測定する方法は?一般的には、少なくとも次の 3 つの指標に焦点を当てます。

  • インターフェースの RT はどのようにしてわかりますか?
  • 異常反応はありますか?
  • 主な減速はどこですか?

モノリシックアーキテクチャ

企業が設立したばかりの初期段階では、次のようなモノリシック アーキテクチャを採用する場合があります。モノリシックアーキテクチャの場合、上記の 3 つの指標をどのように計算すればよいでしょうか?

最も簡単な方法は、AOP を使用することです。

AOP を使用して、特定のビジネス ロジックを呼び出す前後の時間を出力し、全体の呼び出し時間を計算します。 AOP を使用して例外をキャッチし、どの呼び出しが例外の原因になったかを調べます。

マイクロサービスアーキテクチャ

モノリシック アーキテクチャでは、すべてのサービスとコンポーネントが 1 台のマシン上にあるため、これらの監視インジケーターを実装するのは比較的簡単です。

ただし、ビジネスの急速な発展に伴い、次の図に示すように、モノリシック アーキテクチャは必然的にマイクロサービス アーキテクチャへと発展します。

少し複雑なマイクロサービスアーキテクチャ

ユーザーが特定のページが遅いと報告した場合、このページのリクエスト呼び出しチェーンは A→C→B→D であることがわかります。現時点では、どのモジュールが問題の原因となっている可能性があるのか​​をどのように特定すればよいでしょうか?

各サービス A、B、C、D には複数のマシンがあります。リクエストがどの特定のマシンでサービスを呼び出すかをどのように知るのでしょうか?

各リクエストの正確なパスを正確に特定することは不可能であるため、マイクロサービス アーキテクチャにはいくつかの問題点があることは明らかです。

  • トラブルシューティングは難しく、時間がかかります。
  • 特定のシナリオを再現することは困難です。
  • システムパフォーマンスのボトルネック分析は困難です。

分散呼び出しチェーンは上記の問題を解決するために設計されています。主な機能は次のとおりです。

  • データを自動取得します。
  • データを分析して完全な呼び出しチェーンを生成します。リクエストの完全な呼び出しチェーンがあれば、問題を再現できる可能性が高くなります。
  • データの視覚化: 各コンポーネントのパフォーマンスを視覚化することで、システムのボトルネックを特定し、問題を適時に発見できるようになります。

分散トレース システムは、後続のリクエストの特定のリクエスト リンクをそれぞれ適切に特定できるため、リクエスト リンクの追跡を簡単に実装し、各モジュールのパフォーマンス ボトルネックを特定して分析できます。

分散呼び出しチェーン標準: OpenTracing

分散呼び出しチェーンの役割を理解した上で、分散呼び出しチェーンの実装方法とその原則を見てみましょう。

まず、異なる分散トレース システム API 間の非互換性の問題を解決するために、OpenTracing 仕様が誕生しました。

OpenTracing は、アプリケーション/ライブラリとトレースまたはログ分析プログラムの間に位置する軽量の標準化されたレイヤーです。

このように、OpenTracing では、プラットフォームやベンダーに依存しない API を提供することで、開発者がトレース システムの実装を簡単に追加できるようになります。

Java での同様の実装について考えたことはありますか? JDBC を覚えていますか?さまざまなメーカーが実装できる標準インターフェースのセットを提供することで、プログラマーは特定の実装を気にすることなくインターフェースに合わせてプログラムすることができます。

ここでのインターフェースは実際には標準であるため、プラグ可能なコンポーネントを実現するために一連の標準を確立することが非常に重要です。

次に、主に次の 3 つを含む OpenTracing データ モデルを見てみましょう。

  • トレース: 完全なリクエスト リンク。
  • 範囲: 呼び出しプロセス (開始時刻と終了時刻が必要)。
  • SpanContext: TraceId などの Trace のグローバル コンテキスト情報。

これら 3 つの概念を理解することは非常に重要です。これら 3 つの概念をよりよく理解していただくために、特別に次の図を描きました。

図に示すように、注文を行うための完全なリクエストは Trace です。明らかに、このリクエストには、このリクエストを識別するためのグローバル識別子が必要です。各呼び出しは Span と呼ばれ、各呼び出しにはグローバル TraceId が必要です。

このようにして、グローバル TraceId を各呼び出しに関連付けることができます。この TraceId は SpanContext を通じて送信されます。送信する必要があるため、呼び出しはプロトコルに従わなければならないことは明らかです。

図に示すように、トランスポート プロトコルを車、SpanContext を貨物、Span を道路に例えると理解しやすくなります。

これら 3 つの概念を理解したところで、分散トレース システムが統合グラフでマイクロサービス呼び出しチェーンを収集する方法を見てみましょう。

最下層に、静かにデータを収集しているコレクターがあることがわかります。では、コレクターが呼び出されるたびにどのような情報が収集されるのでしょうか?

  • グローバル trace_id: これは明らかなので、各サブコールを元のリクエストに関連付けることができます。
  • 図では span_id: 0、1、1.1、2 となっており、どの呼び出しであるかを識別できます。
  • parent_span_id: たとえば、d を呼び出す b の span_id が 1.1 の場合、その parent_span_id は b を呼び出す a の span_id である 1 になります。このようにして、2 つの隣接する呼び出しを関連付けることができます。

この情報を使用して、コレクターは各通話について次の情報を収集します。

これらのチャート情報に基づいて、呼び出しチェーンの視覚的なビューを次のように描画できることは明らかです。

こうして完全な分散トレースシステムが実現されます。

上記の実装は単純に見えますが、慎重に検討する必要がある問題がいくつかあります。

  • Span データを自動的に収集する方法: ビジネス コードに侵入することなく自動的に収集します。
  • プロセス間でコンテキストを渡す方法。
  • TraceId がグローバルに一意であることを確認する方法。
  • 多数のリクエストを収集するとパフォーマンスに影響しますか?

次に、SkyWalking が上記の 4 つの問題をどのように解決するかを見てみましょう。

スカイウォーキングの原理とアーキテクチャ設計

スパンデータを自動的に収集する方法

SkyWalking はプラグイン + javaagent を使用して Span データの自動収集を実現します。

これにより、コードが非侵入的であることが保証され、プラグイン ベースはプラグイン可能かつ拡張可能であることを意味します (次の記事では、独自のプラグインを定義する方法について説明します)。

プロセス間でコンテキストを渡す方法

データは一般的にヘッダーと本文に分かれていることはご存知でしょう。HTTPhttp にはヘッダーと本文があり、RocketMQ にもメッセージ ヘッダーとメッセージ本文があります。

通常、Body にはビジネス データが含まれるため、Body で Context を渡すのは適切ではありません。図に示すように、コンテキストはヘッダーで渡す必要があります。

Dubbo の添付ファイルはヘッダーと同等なので、添付ファイルにコンテキストを配置することで、コンテキスト転送の問題を解決します。

ヒント: ここでのコンテキスト転送プロセスは Dubbo プラグインによって処理され、企業はそれを認識しません。このプラグインはどのように実装されていますか?以下、それを分析します。

TraceIdがグローバルに一意であることを保証する方法

グローバルな一意性を保証するために、分散 ID またはローカルで生成された ID を使用できます。分散 ID を使用する場合は、番号ジェネレーターが必要です。各リクエストは最初に番号ジェネレータから要求される必要があり、ネットワーク呼び出しのオーバーヘッドが発生します。

そこで、SkyWalking は最終的に、高性能で有名な Snowflow アルゴリズムを使用して ID をローカルで生成する方法を採用しました。

スノーフレークアルゴリズムによって生成されたID

ただし、Snowflake アルゴリズムには、時間のロールバックというよく知られた問題があり、これにより生成された ID が重複する可能性があります。では、SkyWalking は時間巻き戻しの問題をどのように解決するのでしょうか?

ID が生成されるたびに、ID が生成された時刻 (lastTimestamp) が記録されます。現在の時刻が ID が最後に生成された時刻 (lastTimestamp) よりも小さい場合は、時間のロールバックが発生したことを意味します。このとき、TraceId として乱数が生成されます。

学生の中には、ここでもっと真剣になり、生成された乱数が生成されたグローバル ID で繰り返されると考える人もいるかもしれません。そのため、検証の別のレイヤーを追加した方がよいでしょう。

ここでは、システム設計におけるトレードオフについて話す必要があります。まず、生成された乱数に対して一意性チェックを実行すると、間違いなく呼び出しのレイヤーが追加され、一定のパフォーマンスの低下が発生します。

しかし、実際には、タイムロールバックが発生する確率は非常に小さく(発生すると、マシンタイムの乱れにより業務に大きな影響が出るため、マシンタイムの調整は細心の注意を払って行う必要があります)、生成された乱数が重なる確率も非常に小さいのです。すべての要素を考慮すると、ここでグローバル一意性チェックの別のレイヤーを追加する必要はありません。

技術的なソリューションを選択するときは、過剰な設計を避ける必要があります。多すぎるのも少なすぎるのも同じくらい悪いからです。

すべてのコレクションはパフォーマンスに影響しますか?

リクエストの数が非常に多いため、リクエスト呼び出しごとにデータが収集されると、データの量は間違いなく非常に大きくなります。しかし、逆に考えてみると、リクエストごとにデータを収集することが本当に必要でしょうか?

実際、それは必要ありません。データの一部だけをサンプリングするようにサンプリング周波数を設定できます。 SkyWalking は、デフォルトでサンプリング頻度を 3 秒ごとに 3 回に設定し、図に示すように、残りのリクエストはサンプリングされません。

このサンプリング周波数は、実際にコンポーネントのパフォーマンスを分析するのに十分です。 3 秒間に 3 回データをサンプリングすると、どのような問題が発生しますか?

理想的には、各サービス コールは同じ時点で発生します (以下に示すように)。この場合、毎回同じ時点でサンプリングを行うのは確かに良い考えです。

ただし、実稼働環境では、ネットワーク呼び出しの遅延により、各サービス呼び出しを同時に実行することは基本的に不可能です。実際の通話状況は次のようになると考えられます。

この場合、一部の呼び出しはサービス A でサンプリングされますが、サービス B と C ではサンプリングされず、呼び出しチェーンのパフォーマンスを分析できなくなります。では、SkyWalking はこの問題をどのように解決するのでしょうか?

解決策は次のとおりです。アップストリームがコンテキスト(アップストリームがサンプリングされたことを示す)を伝送する場合、ダウンストリームは強制的にデータを収集します。これにより、リンクの整合性が保証されます。

スカイウォーキングインフラ

SkyWalking は次のアーキテクチャに基づいています。ほぼすべての分散呼び出しは、次のコンポーネントで構成されていると言えます。

最初のステップは、もちろん、ノード データのスケジュールされたサンプリングです。サンプリング後、データは定期的にレポートされ、ES や MySQL などの永続レイヤーに保存されます。データがあれば、データに基づいた視覚的な分析が自然に実行できます。

SkyWalking のパフォーマンスはどうですか?

次に、SkyWalking のパフォーマンスについて、皆さんもっと気になるはずですので、公式の評価データを見てみましょう。

図では、青は SkyWalking なしのパフォーマンスを表し、オレンジは SkyWalking ありのパフォーマンスを表します。上記データはTPSが5000のときに測定されたものです。

CPU、メモリ、応答時間のいずれにおいても、SkyWalking の使用によるパフォーマンスの低下はほぼ無視できることがわかります。

次に、SkyWalking と業界でよく知られている別の分散トレースツールである Zipkin および Pinpoint との比較を見てみましょう (比較は、サンプリングレートが 1 秒あたり 1 回、スレッド数が 500、リクエストの総数が 5000 の場合に行われます)。

クリティカル応答時間に関しては、Zipkin (117ms) と PinPoint (201ms) が SkyWalking (22ms) に比べて大幅に劣っていることがわかります。

パフォーマンス損失指標から見ると、SkyWalking が勝利です!

別の指標、つまりコードに対する侵入度を見てみましょう。 ZipKin はアプリケーションにポイントを埋め込む必要があるため、コードへの侵入が強くなりますが、SkyWalking は javaagent+plug-in を使用してバイトコードを変更し、コードへの侵入を防ぎます。

SkyWaking は、優れたパフォーマンスとコード侵入に加えて、次のような利点もあります。

  • 複数の言語と豊富なコンポーネントのサポート: 現在、Java、.Net Core、PHP、NodeJS、Golang、LUA 言語をサポートしています。また、Dubbo や MySQL などの一般的なコンポーネントもサポートしており、そのほとんどは私たちのニーズを満たすことができます。
  • 拡張性: 要件を満たさないプラグインについては、SkyWalking ルールに従って手動で作成できます。新しく実装されたプラグインはコードに侵入しません。

分散コールチェーンに関する当社の実践

弊社のSkyWalkingアプリケーションアーキテクチャ

上記から、SkyWalking には多くの利点があることがわかります。それで、そのコンポーネントをすべて使用するのでしょうか?実はそうでもないんです。弊社のアプリケーション アーキテクチャを見てみましょう。

図からわかるように、サンプリングには SkyWalking Agent のみを使用し、「データのレポートと分析」、「データの保存」、「データの視覚化」という他の 3 つのコンポーネントは使用しませんでした。では、なぜ SkyWalking の完全なソリューションを使用しないのでしょうか?

なぜなら、SkyWalking に接続する前に、Marvin 監視エコシステムはすでに比較的完成していたからです。

システム全体を SkyWalking に置き換える場合、まず、ほとんどのシナリオでは Marvin がニーズを満たすことができるため、SkyWalking は必要ありません。第二に、システムを交換するコストが高い。 3 番目に、システムを再接続すると、ユーザーの学習コストが非常に高くなります。

このことから、どんな製品でも主導権を握ることが重要だということもわかります。後続製品の交換コストは非常に高くなります。主導権を握るということは、ユーザーの心を掴むことを意味します。これはWeChatと同じで、UIと機能は優れているものの、主導権が失われているため、海外ではWhatsappと競争することはできません。

別の観点から見ると、最良または最も適切なアーキテクチャは存在しません。建築設計の本質は、現在のビジネスシナリオ間のバランスをとることです。

当社のスカイウォーキング変革実践

当社は主に以下の変革と実践を行ってきました。

  • プレリリース環境ではデバッグのために必須のサンプリングが必要です
  • よりきめ細かなサンプリングの実現
  • ログにトレースIDを埋め込む
  • 自社開発のSkyWalkingプラグイン

① プレリリース環境ではデバッグのためサンプリングが必須

上記の分析から、Collector がバックグラウンドで定期的にサンプリングしていることがわかります。これっていいじゃないですか?強制サンプリングを実装する必要があるのはなぜですか?

または、トラブルシューティングして問題を特定するために、オンラインで問題が発生し、それをプレリリースで再現し、このリクエストの完全な呼び出しチェーンを確認したい場合があり、そのためプレリリースで強制サンプリングを実装する必要があります。

そこで、Skywalking の Dubbo プラグインを修正して強制サンプリングを実装しました。

強制的にサンプリングを行うことを示すために、force_flag=true のようなキーと値のペアをリクエスト クッキーに追加します。

ゲートウェイはこの Cookie を受信すると、キーと値のペア force_flag=true を Dubbo 添付ファイルに追加します。

次に、Skywalking の Dubbo プラグインはこれを使用して、強制サンプリングであるかどうかを判断できます。この値がある場合は強制サンプリングとなります。そのような値がない場合、通常の時間指定サンプリングが実行されます。

②よりきめ細かなサンプリングを実現しますか?

これは、よりきめ細かいサンプリングと呼ばれます。まず、Skywalking のデフォルトのサンプリング方法である統合サンプリングについて見てみましょう。

このメソッドは、デフォルトで 3 秒以内に最初の 3 回をサンプリングし、他のすべてのリクエストを破棄することがわかっています。これには問題があります。

このマシンでは 3 秒以内に複数の Dubbo、MySQL、および Redis 呼び出しが行われると想定します。最初の 3 つの呼び出しが Dubbo 呼び出しの場合、MySQL や Redis などの他の呼び出しはサンプリングされません。

そこで、Skywalking を修正し、次のようにグループ サンプリングを実装しました。

つまり、Redis、Dubbo、MySQL などのサンプリングは 3 秒以内に 3 回実行されるため、この問題は回避されます。

③ログにTraceIdを埋め込むには?

出力ログに TraceId を埋め込むと、問題のトラブルシューティングが容易になるため、TraceId を出力することが非常に重要です。ログに TraceId を埋め込むにはどうすればいいですか?

log4j を使用するので、log4j のプラグインの仕組みを理解する必要があります。 Log4j を使用すると、プラグインをカスタマイズしてログ形式を出力することができます。まず、ログ形式を定義し、次のようにカスタム ログ形式に %traceId をプレースホルダーとして埋め込む必要があります。

次に、log4j プラグインを次のように実装します。

まず、log4j プラグインは、LogEventPatternConverter クラスを継承し、標準プラグインを使用するプラグインとして自身を宣言するクラスを定義する必要があります。

@ConverterKeys アノテーションは、置換するプレースホルダーを指定し、それを format メソッドで置換します。

この方法では、必要な TraceId が次のようにログに表示されます。

④どのようなSkywalkingプラグインを開発しましたか?

SkyWalking は多くのプラグインを実装していますが、Memcached と Druid 用のプラグインは提供されていないため、次の 2 つのプラグインをその仕様に従って独自に開発しました。

プラグインを実装するにはどうすればいいですか?主に 3 つの部分で構成されていることがわかります。

  • プラグイン定義クラス: プラグインの定義クラスを指定します。ここで指定した定義クラスに基づいて、最終的にプラグインとしてパッケージ化され、生成されます。
  • インストルメンテーション: 強化するアスペクト、ポイントカット、およびどのクラスのどのメソッドを指定します。
  • インターセプター: ステップ 2 で、メソッドのプリアンブル、ポストアンブル、または例外に拡張ロジックを書き込むかどうかを指定します。

まだ理解していないかもしれないので、Dubbo プラグインを例に挙げてみましょう。 Dubbo サービスでは、Netty がメッセージを受信して​​処理のためにビジネス スレッド プールに送信してから、ビジネス メソッドが実際に呼び出されるまでの間に、各リクエストが 12 個を超えるフィルターによって処理されることがわかっています。

MonitorFilter は、クライアントからのすべてのリクエストやサーバーによって処理されるリクエストをインターセプトできるため、MonitorFilter を拡張できます。

Invoke メソッドを呼び出す前に、グローバル TraceId が Invocation の Attachment に挿入されるため、要求が実際のビジネス ロジックに到達する前にグローバル TraceId が存在することが保証されます。

したがって、明らかに、プラグイン内で拡張するクラス (MonitorFilter) を指定し、そのメソッド (Invoke) を拡張する必要があります。この方法にはどのような強化を加えるべきでしょうか?

これがインターセプターの機能です。 Dubbo プラグイン (DubboInstrumentation) のインストルメンテーションを見てみましょう。

コードに記述されているインターセプターが何を行うかを見てみましょう。主な手順は以下のとおりです。

まず、beforeMethod は、MonitorFilter のinvoke メソッドを実行する前に、ここでのメソッドが呼び出されることを意味します。対応するものは afterMethod であり、これは、invoke メソッドの実行後に拡張ロジックが実行されることを意味します。

次に、ポイント 2 と 3 から、コンシューマーとプロバイダーの両方がグローバル ID を適切に処理していることがわかります。

これにより、実際のビジネス レイヤーに到達したときにグローバル Traceid が使用できるようになります。 Instrumentation と Interceptor を定義した後、最後のステップは、skywalking.def で定義されたクラスを指定することです。

  1. // skywalking-plugin.def ファイル
  2. dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation

このようにパッケージ化されたプラグインは、MonitorFilter の Invoke メソッドを拡張し、Invoke メソッドが実行される前に、グローバル TraceId を Attachment に挿入します。これらはすべて静かに行われ、コードに影響を与えることはありません。

要約する

この記事では、最も単純なものから最も複雑なものまで、分散トレース システムの原理を紹介します。皆様もその役割や動作の仕組みについてより深く理解していただけたと思います。

特に注意すべき点は、特定の技術を導入する際には、SkyWalking には 4 つのモジュールがあり、当社ではその Agent サンプリング機能のみを使用しているように、既存の技術アーキテクチャと組み合わせて最も合理的な選択を行う必要があるということです。最良の技術というものは存在せず、最も適した技術があるだけです。

この記事を通じて、SkyWalking の実装メカニズムについて、誰もがより明確に理解できるようになると思います。この記事では、SkyWalking のプラグイン実装についてのみ紹介します。しかし、それは結局産業グレードのソフトウェアです。その奥深さを理解するには、ソースコードをもっと読む必要があります。

著者: コードシー

編集者:タオ・ジアロン

出典: 公開アカウント sea (ID: seaofcode) から転載

<<:  データセンターが繁栄し続ける5つの理由

>>:  クラウドのために生まれた「クラウド ネイティブ」が、なぜますます重要になっているのでしょうか?

推薦する

rapidvps-フルマネージドVPS/1Tトラフィック/Gポート/20%割引

rapidvps は、米国フロリダ州の VPS 販売業者です。会社として登録され (2007 年)、...

Urpadが再び登場、SSDも搭載

Urpad の以前の年間支払額 19 ドルはそのままで、現在は新しいプロモーションがあります。768...

なぜ Baidu のランキングは 2018 年にこれほど悪く、トラフィックが減少しているのでしょうか?

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っていますここ数ヶ月...

ウェブマスターが知っておくべき360度の包括的な検索知識

360総合検索は、前回の3Bサイト事件以降、沈静化しているようで、大きなニュースは漏れていません。3...

IoT とエッジ コンピューティングの将来はどうなるのでしょうか?

モノのインターネットとエッジコンピューティングは、将来の技術開発に関する議論において長い間注目されて...

AppleはiOS 6で新しいマッピング技術を取得する予定と報じられている

Google のマップデータスイッチボードから離れた社内ソリューションは、Apple にとって差し迫...

タオバオの信用詐欺に対するゼロトレランスにより、多くの個人が店舗を閉鎖することになった。

最近、多くのタオバオストアが閉鎖されました。10月28日、タオバオは初の公式発表を発表し、「信用詐欺...

SEOについて語るにはまだ時期尚早です。国内のSEO業界はまだ発展の可能性があります。

SEOに注目している方なら、最近アメリカの有名な経済雑誌Forbesに掲載され、A5とchinazに...

SEO初心者は傲慢さを捨てなければならない

今、SEO業界に参入しようと言うと、他の人から強く思いとどまられるでしょう。なぜなら、現状では、情報...

パフォーマンスが160%向上しました!アリババクラウド、第7世代ECS、クラウドネイティブデータベースPolarDB-Xなど主要新製品をリリース

アリババクラウドは6月9日、第7世代ECS、POLARDB-Xデータベース、ビジュアルインテリジェン...

racknerd: バレンタインデー特別格安 VPS、年間 $13.93、KVM/768M メモリ/12g ハードディスク/2T トラフィック

Racknerd の毎年恒例のバレンタインデー イベントが早くも始まり、特に安価な VPS 2 つが...

利益に関するニュースが次々と流れてくる中、共同購入ウェブサイトの厳しい冬は終わりを迎えるのでしょうか?

カオス最近、共同購入サイトに関するニュースが再び人々の目に留まり始めていますが、そのニュースはすべて...

店舗経営に役立つ12のデータ

(1)販売1) 売上高は店舗のビジネス動向を反映します。過去の販売データや地域産業の発展状況を踏まえ...

Gelhost - 年間 25 ドル / KVM / 256 MB RAM / 7 GB SSD / 177 GB 帯域幅 / シカゴ

Gelhost (AMVPSGelNet LLC) は、2011 年に設立されたホスティング プロバ...