基本コンセプト

最新のIT環境は、少数のモノリシックアプリケーションから数千のマイクロサービスに至るまで、さまざまなコンポーネントで構成されています。 これらのコンポーネントは、絶えず変化する構成のアプリケーションコードによって接続され、絶え間ない技術的およびビジネス的な変化に適応します。 トレースを使用して、さまざまなコンポーネント間の相互作用と、コンポーネント間で受け渡されるメッセージを理解します。 サービスシステムがどのように連携し、その後のコンポーネント障害の影響を理解するために、独自のダイナミックグラフを使用して、基盤となるサービス、アプリケーション、およびシステムインフラストラクチャに関する情報でトレースを強化します。

トレースとは、単一の要求とそのサービスシステムを通るパスの表現です。 これは、顧客のブラウザーによって開始された要求の直接的な結果である可能性がありますが、スケジュールされたジョブまたはその他の内部実行によって開始される可能性もあります。 各トレースは、ひとつ以上の呼び出しで構成されます。

コールとは2つのサービス間の通信を表します。 エンドポイント、パラメータなどのタイプ固有のペイロード、エラーコード、詳細など、発信者と着信者の詳細情報で構成されます。

コール自体は通常、ひとつまたは2つのスパンで作成されます。 ほとんどのユーザーとユースケースでは、コールの概念は、開始して多くの問題を解決するのに十分なはずです。 より深く掘り下げるには、以下の追記コンセプトを参照してください。

トレースの分析

トレースは、Instanaのアプリケーションビューの各セクションを支えており、分析ビューで詳細に調べることができます。 分析ビューでは、Instanaによって収集されたトレースと呼び出しを調査できます。 各呼び出しでアプリケーション全体がどのように動作するかを理解するために、システムに着信する呼び出しを監視します。

アプリケーションおよびサービスダッシュボードのトレース

analyze-calls

アプリケーションとサービスのダッシュボードから、ユーザーは基盤となるトレースに飛び込むことができます。 各ダッシュボードの[呼び出しの分析]ボタンは、ページの上部にあります。 これを選択すると、アプリケーション、サービス、およびエンドポイントごとに「コールを分析」でき、Instanaが提供するデータをサービス、エンドポイント、およびコール名ごとに分類できます。

ビューを分析

analyze-view

分析ビューでは、任意のタグでトレースまたは呼び出しをフィルタリングおよびグループ化できます。 フィルターは AND ロジックオペレーターで連結されているので、トレースまたは呼び出しはすべてのフィルターに一致する必要があります。 デフォルトのグループ化はエンドポイント名です。 グループ化を削除して、フィルターに一致する個々のトレースと呼び出しを検査できます。 上記の例は、 「application = Catalogue」「service = catalogue」 エンドポイント名でグループ化されたコールを表示します。

application.nameservice.nameendpoint.name タグ、および agent.taghost.name などのインフラストラクチャエンティティタグは、呼び出しの発信元と宛先の両方に適用できます。 デフォルトでは宛先に適用されますが、フィルターの編集ダイアログでソースに変更できます。 送信元と宛先を組み合わせることで、「これらの2つのサービス間のすべての呼び出しを表示する」または「agent.zone の「本番」から agent.zone の「テスト」に向けて発行されたすべての呼び出しを表示する」などのクエリを表現できます

送信元と宛先もグループ化に使用できるため、「このひとつのサービスに対するすべての呼び出しを発信者別に分類して表示する」などのクエリを表現できます。

発信元または宛先にフィルターとグループを適用するこのオプションは、call.http.pathcall.tag などの呼び出しタグでは使用できません。これらは、呼び出し自体のプロパティであり、発信元または宛先に依存しません。

ソースおよび宛先によるグループ化は、トレースの分析でも使用できません。そのビューで使用可能なグループは、特定のコールのソースまたは宛先から独立しているためです。

トレースビュー

グループを選択し、分析ビューからトレースを選択すると、トレースビューが開きます。 呼び出しを選択すると、トレースのコンテキストでこの特定の呼び出しが開きます。

trace-view-1

上記は、タイムラインとサービスリストを含む特定のトレースの概要です。 概要には以下が含まれます。

  • トレース名(通常はHTTPエントリ)
  • 発生したサービスの名前
  • タイプまたは技術
  • コアKPI:
    • 他のサービスへの呼び出し
    • 合計レイテンシー
    • トレース内のエラー

タイムラインは、トレースがいつ開始されたか、およびトレース全体でサービスが呼び出された時系列順を示します。 呼び出しチェーンはルート要素(または、スパンと呼びます)からハングします。 単純な3層システムでは、一般的な深さは約4レベルになりますが、分散サービスまたはマイクロサービスアーキテクチャを備えたシステムでは、はるかに長いつららが見られます。 そのグラフは、トレースの非常に長いサブコール、またはデータベースエントリごとにひとつのHTTPコールのような特定の定期的なコールパターンがある場合に、コール構造の良い印象を与えます。 次に、グラフ内のスパンをクリックすると、その詳細にジャンプします。

さまざまなサービスには独自の色があります(この例ではshop = blue、productsearch green)。 特定のコールにカーソルを合わせると、時間がかかった場所が詳細に表示されます:セルフ(コール内)、別のコールまたはネットワークで待機中。 呼び出しをクリックすると、トレースツリーの呼び出しがさらに下に表示されます。

以下のサービスリストは、サービスごとのすべてのコールをまとめたもので、コール数、集計時間、発生したエラーの概要をすばやく確認できます。

トレースツリーと呼び出しの詳細

trace-view-2

トレースツリーは、アップストリームおよびダウンストリームのサービスコールの構造に関する詳細な洞察を提供します。 呼び出しのタイプを示し、ツリーの個々の部分を展開および縮小することにより、トレースツリーを探索できます。 また、コールのサービスおよびエンドポイントのダッシュボードに直接アクセスできます。

通話をクリックすると call detail サイドバーが開きます。 エラーやステータスコード、スタックトレースなどの呼び出しの詳細、およびその呼び出し中にキャプチャされた詳細が表示されます。

ログとエラーのキャプチャ

Instanaは、サービスが不正な応答を返すか、ERROR または WARN レベル(またはフレームワークに応じて同様)のログが検出されたときに自動的にエラーをキャプチャします。

ショートエグジットコールの自動集約

Instanaは常に、実際のアプリケーションへの影響を最小限に抑えながら、サービスの相互作用を最大限に理解できるよう努めています。 ただし、特定のシナリオでは、Instanaがそれを達成するためにデータをドロップする必要があります。 システムで非常に一般的な問題は、いわゆる1 + Nクエリの問題です。これは、コードが1回データベース呼び出しを実行してアイテムのリストを取得し、続いて個々のアイテムを取得するN個の個別呼び出しを実行する状況を説明します。 この問題は通常、ひとつの呼び出しを実行し、他の呼び出しに参加するだけで修正できます。

パラメータキャプチャ

現時点では、Instanaのトレースセンサーは、影響の懸念により、メソッドパラメーターまたはメソッドの戻り値を自動的にキャプチャしません。 SDKを使用して、追加データをオンデマンドでキャプチャできます。

長時間実行タスク

タイムアウト、高負荷、またはその他の環境条件により、コールが応答するまでにかなりの時間が必要になる可能性があります。 トレースには、数十または数百のそのような呼び出しを含めることができます。 すべての呼び出しが応答してトレース情報を配信するまで待てないため、長時間実行されているスパンはプレースホルダーに置き換えられます。 スパンが最終的に戻ると、プレースホルダーは再び正しい呼び出し情報に置き換えられます。

過去のデータ

Instanaは、すべてのトレースと呼び出しを7日間保存します。 この期間を過ぎても、当社の保持戦略は統計的に重要な痕跡と呼び出しを保持し、無制限のストレージの増加を防ぎます。

履歴データを見ると、

historic-data-indicator-old

 

 インジケータが表示されます。

まれに発生するトレースと呼び出しは、このようなシナリオでは表されない場合があります。

追記コンセプト

ほとんどのユーザーとユースケースでは、開始して多くの問題を解決するのにコアの概念で十分です。 次のセクションは、アーキテクトと関心のある開発者が、基礎となる概念をより深く掘り下げて理解するためのものです。

用語

トレース

トレースは、単一のリクエストと、サービスシステムを通るそのパスの表現です。 これは、顧客のブラウザーによって開始された要求の結果である可能性がありますが、スケジュールされたジョブまたはその他の内部実行によって開始される可能性もあります。 各トレースは、ひとつ以上の呼び出しで構成されます。

コール

呼び出しは、2つのサービス間の通信を表し、要求と応答として見ることができますが、応答は非同期にすることができます。 呼び出しは、特定のRPCまたはサービス呼び出しに対応するデータと時間の測定値のセットです。 たとえば、HTTPまたはデータベース呼び出しを使用できます。 Instanaでは、UIで強調表示することで、HTTP、メッセージング、データベース、バッチ、内部などの呼び出しの種類を簡単に理解できます。

このデータをキャプチャするために、Instanaは発信側と着信側の両方で測定します。 シナリオによっては、監視ツールが発信者側、着信者側、または両側で測定できるため、これは分散システムでは重要です。 分散トレースでは、これらの個々の測定値はスパンと呼ばれます。

内部呼び出しは、サービス内で実行される作業を表す特別な種類の呼び出しです。 カスタムトレースを介して送信された中間スパンから作成できます。

呼び出しは、エラーが発生した操作を表す場合があります。 たとえば、HTTP操作を表す呼び出しは5xxステータスコードになり、Java RMIを介したAPIの呼び出しにより例外がスローされる場合があります。 そのような呼び出しは間違いとされ、InstanaのUIではそのように記述されます。  ステータスコード4xxをもたらすHTTP呼び出しは Studio上ではサポートされていません。 4xxはクライアント側のエラーとして定義されているため、エラーと見なされます。

trace-view-3

上の画像に示すように、エラーログは、関連付けられている呼び出しに表示されます。 Instanaは、レベル WARN およびERROR(およびロギングフレームワークに応じて同等)のログを自動的に収集します。 上の画像では、呼び出しにエラーがあり、エラーログがひとつ関連付けられていることがわかります。 ただし、一般的に、コールはエラーログに関連付けられていないため、エラーが発生する可能性があり、その逆も同様です。

スパン

スパンは、コード実行のタイミング(文字通り、開始時間と終了時間を伴うアクション)を表します。 また、タイムスタンプと期間の両方で構成されるデータのセットも保持します。 異なるタイプのスパンには、これらの64つまたは複数のセットを含めることができ、メタデータアノテーションを備えています。 すべてのトレースモデルは、階層セット内のスパンのブロックで構成され、親(「呼び出し元」)スパンと子(「呼び出し先」)スパンの間の参照に使用される64ビット識別子によって順序付けられます。 トレースの最初のスパンはルートとして機能し、その64ビット識別子はトレース全体の識別子と見なされます。

特定のサービスの最初のスパンは、コールがサービスに入ったことを示し、 エントリースパン (Dapperペーパーでは、これは「サーバースパン」と名付けられています)。 サービスを離れるコールのスパンが呼び出されます エグジットスパン (Dapperペーパーでは、これは「クライアントスパン」と名付けられています)。 エントリスパンとエグジットスパンに加えて、中間スパンはコードの重要なセクションをマークするため、トレースランタイムは正しいコードに明確に帰属することができます。

call-span-model

ちなみに、「スパン」という名前は、Googleの有名なDapperペーパーに由来し、「タイムスパン」の略です。

分散トレース理論

スパンは、タイムスタンプと期間の両方で構成されるデータのセットを搬送します。 異なるタイプのスパンには、これらの64つまたは複数のセットを含めることができ、メタデータアノテーションを備えています。 すべてのトレースモデルは、階層セット内のスパンのブロックで構成され、親(「呼び出し元」)スパンと子(「呼び出し先」)スパンの間の参照に使用される64ビット識別子によって順序付けられます。 トレースの最初のスパンはルートとして機能し、その64ビット識別子はトレース全体の識別子と見なされます。

特定のサービスの最初のスパンは、コールがサービスに入ったことを示し、エントリスパンと呼ばれます(Dapperの論文では「サーバースパン」と呼ばれています)。 サービスを離れるコールのスパンは、エグジットスパンと呼ばれます(Dapperペーパーでは「クライアントスパン」です)。 中間スパンはコードの重要なセクションをマークするため、トレースランタイムは正しいコードに明確に帰属することができます。 サービス全体の一連のスパンを追跡するために、Instanaはインストルメント済みエグジットを使用して相関ヘッダーを自動的に送信し、それらの相関ヘッダーはInstanaのエントリによって自動的に読み取られます。 HTTPトレースヘッダーを参照してください。

各スパンには、HTTPコールやデータベース接続などのタイプが関連付けられています。 スパンタイプに応じて、追加のコンテキストデータもスパンに関連付けられます。

Instanaで実装されたトレースについては、Googleでの分散トレースを説明する論文であるDapperと、Twitterで開発されたDapperのようなトレースである「Zipkin」の開発者が開始したOpenTracing Initiativeからインスピレーションを得ました。 GoogleとTwitterはどちらも高度に分散されたサービスアーキテクチャに直面しており、現在多くのマイクロサービスユーザーが抱えている問題にすでに対処しています。

ハイライトする価値のあるDapper / OpenTracingの重要なポイントは次のとおりです。

  • 実行中のコードの正確な行は、操作または開発のどちらにとっても興味深いものではありません。。 操作については、コードの変更はほとんど不可能です。これにより、ほとんどのAPMツールが開発中心のツールに変わります。 しかし、開発部門であっても、コールスタックに含まれるコードのデータのほとんどはノイズです。 変更できないランタイムコード、フレームワークコード、またはサードパーティコードのいずれかです。
  • サービスとコンポーネント間の相互作用が重要です。 ほとんどの問題は、障害のあるコンポーネントまたはサービスが特定されたときに解決できます。 内部エラーが発生する可能性がありますが、サービスの可用性と相互作用を監視することが最も重要です。 また、Instanaはトレースを使用して、ダイナミックグラフに寄与するコンポーネントの論理的な依存関係を理解します。
  • リモート呼び出しは、固有の低速性のために特に興味深いものです。 多くのAPMツールはプロセスコールスタックに焦点を当てていますが、ほとんどの場合、これらは非常に高速です。 リモートサービスにアクセスするときに、パフォーマンスの低下が最もよく発生します。
  • 一時的な問題はトラブルシューティングに時間を浪費するものであり、すべてのトレースの非常に低い割合を調べても洞察を得ることができます。 すべてのエンジニアは自分のコードを可能な限り高速に実行することを望んでいますが、平均より100ミリ秒遅い場合でも、数千の呼び出しのうちひとつだけを調査するのは非効率的です。

トレースの動機

トレースは、すべてのアプリケーションパフォーマンス管理ツールの中核です。 Gartnerによって「ユーザー定義のトランザクションプロファイリング」と呼ばれ、APMツールのユーザーにとって2つの重要な価値があります。

  • 関係するすべてのコンポーネントを通るトランザクションフローを理解して、アプリケーションアーキテクチャと分散呼び出しパターンのより良いビューを取得します。
  • 実行時間を含むメソッド/コードレベルの詳細を取得して、パフォーマンスの問題をトラブルシューティングします。

現在の世代のAPMツールとそのトレース機能は、主に2番目のポイントである「コールスタック」に焦点を当てています。 Instanaでは、このアプローチはいくつかの理由で理想的ではないことがわかりました。代わりに、特に高度に分散されたマイクロサービス環境を扱う場合、最初の価値に焦点を当てています。

コールスタック

トレースを理解するための段階を設定するために、コールスタックがどのように機能するかを簡単に紹介します。 コールスタックは、コード実行の順序付きリストであり、コードが他のコードを呼び出すたびに、新しいコードがそのスタックの一番上に配置されます。 コールスタックは、すべてのプログラミング言語のランタイムで使用され、通常は、エラーが発生した呼び出しを「トレースバック」できるため、エラーが発生したときに「スタックトレース」として出力されます。

たとえば、「Appleは数字ではありません」というエラーメッセージが表示される場合があります。 コールスタックと組み合わせることで、複雑なシステムで実際にエラーが発生した場所を絞り込むことができます。 NumberUtilアルゴリズムは多くの場所で使用される可能性があるため、通常、メッセージだけでは不十分です。

Thread.run()
  HttpFramework.service()
    HttpFramework.dispatch()
      ShoppingCart.update()
        ShoppingCart.updateCart()
          ShoppingCart.parseQuantity()
            ShoppingCart.convertParams()
              NumberUtil.convert()  <-- Error: "Apple is not a number"

開発者は、このコールスタックを使用して、エラーから関連するビジネスメソッド(ShoppingCart.parseQuantity())までさかのぼって、エラーが発生した理由をよりよく理解できます。

分散トレース

サービス指向アーキテクチャが10年前に登場したとき、コールスタックはバラバラにされていました。 「ShoppingCart」ロジックは現在サーバーAにあり、「NumberUtil」はサーバーBにあります。

突然、サーバーBのエラートレースには解析エラーの短いコールスタックのみが含まれ、サーバーAで新しいエラーが生成され、サーバーBで問題が発生しましたが、問題は示されませんでした。 トラブルシューティングが簡単な単一のエラーコールスタックの代わりに、ユーザーは2つのエラーを持つ2つのコールスタックになりました。 さらに悪いことに、2つの間に接続がなかったため、同時に両方にアクセスできないことがありました。

サーバーA:

Thread.run()
  HttpFramework