Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、トレース、ログ、メトリクスを関連付け、Grafana、Promtail、Prometheusを利用した横断的なオブザーバビリティ基盤を紹介します。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。前回は、OpenTelemetryやObservabilityの概要について紹介し、簡単なサンプルアプリケーションを使った分散トレーシングの方法を紹介しました。トレースを収集、可視化することによって、マイクロサービスをまたがるリクエストの追跡が容易になりました。
しかし、分散トレーシングだけではOpenTelemetryの真の力を発揮できません。トレースによって「どの処理に時間がかかっているのか」「どの処理にエラーが発生しているのか」を知ることはできても、その原因を特定するには不十分なケースは多々あります。そのような場合、問題があるトレースやスパンに対応するログやメトリクスを調べることで原因の特定に役立つことがありますが、異なるテレメトリーを関連付けながら調査するのは容易ではありません。
OpenTelemetryを用いることで、これらのテレメトリーを関連付けることができます(下図の「OpenTelemetry Collection」)。それによって、問題のあるトレースに対応するログやメトリクスを調べることができ、トラブルシューティングを効率化できます。
今回は、OpenTelemetryやオープンソースソフトウェア(OSS)のモニタリングツールを用いてテレメトリーを関連付けることで、Grafanaダッシュボード上でログ、トレース、メトリクス間を行き来できるような三位一体の、いわば「シン・オブザーバビリティ基盤」を紹介します。
前回紹介したOpenTelemetry Collection(下図)では、テレメトリーを横串で探索できる情報(例えば、テレメトリー取得時間やクラスタ、Pod、コンテナなどのリソース情報、トレースIDやスパンIDなどのトレース情報)を付与します。
このようにログ、トレース、メトリクスといったテレメトリーを“関連付ける”ことによって、さまざまな恩恵、特にトラブルを生じた際の解析性向上に寄与できます。下記はトラブルシューティングの一例です。
テレメトリー同士が関連していない場合、ログコンソールやダッシュボードを用いながら、勘や経験を頼りにテレメトリー間を関連付けることもしばしばあることでしょう。しかし一刻を争う有事の際に、原因特定までのリードタイムは最小化できることが望ましいです。
テレメトリー間を関連付け、テレメトリーから対応するテレメトリーを即座に特定できることは、上記のような場合大きなアドバンテージになります。特に動的にリソースが変化するクラウドネイティブ環境において、テレメトリー間の関連性を保ち続ける(見失わない)ことが非常に重要です。
各テレメトリー間を関連付けるためにはどのようにすればいいのでしょうか? OpenTelemetryのコンセプトに触れながら説明します。
OpenTelemetryでは各テレメトリーに以下のような情報を付与することで、各種オブザーバビリティーデータを関連付けます。
繰り返しますが、テレメトリー間の関連付けは、各テレメトリーのフィルタリングやクエリといった分析機能の基盤となります。タイムスタンプやリソース情報を用いて、特定時間の特定コンポーネント(例えば、KubernetesのnamespaceやPod、コンテナ単位)のテレメトリーを横串で調査することが可能になります。
トレースIDやスパンIDによる関連付けは、一連のリクエストの過程で関係のあるテレメトリーを抽出できるので非常に重要です。特にマイクロサービスアーキテクチャではサービス間のつながりが複雑化し、とあるサービスでの影響が離れたサービスで検知されるような場合が多くあります。
このような場合に、エラーログからログに付与されたトレースIDを介して、トレース全体を調査するといったトラブルシューティングの流れは有効的です。
本稿では、トラブルシューティング時に大きな効果をもたらす「トレースIDやスパンIDによる関連付け」に着目し、テレメトリーにトレースIDやスパンIDを付与することで関連付け、「Grafana」などのOSSツールを使った実践的な分析基盤を構築します。
本稿で構築するOpenTelemetryを用いたテレメトリーを関連付けて収集するためのアーキテクチャは下図のようになります。
今回扱うテレメトリーの収集方法は次の通りです。
各テレメトリーの関連付けの方法を整理します。
テレメトリー | 関連付け | バックエンド |
---|---|---|
ログ | ログフィールドにトレースID、スパンIDを付与 | Grafana Loki |
トレース | トレースID、スパンIDを保持 | Grafana Tempo |
メトリクス | 「Exemplar」(後述)を用いてトレースIDを付与 | Prometheus |
それぞれ関連付いたテレメトリーをモニタリングバックエンドツールに送信し、Grafanaダッシュボード上で可視化します。
ここでは、ログにトレースID、スパンIDを付与し、トレースとログを関連付ける方法を説明します。
ログにトレースID、スパンIDを付与する方法は、OpenTelemetryにおけるログの収集方法によって異なります。まず、ログの収集方法からです。
「OpenTelemetryの仕様」では下図の2つの方法を紹介しています。
アーキテクチャ的には、分散トレーシングの構成同様、【1】の方法がシンプルですが、現状OpenTelemetryのログライブラリの実装は過渡期であり、言語(JavaやPythonなど)によって「experimental」ステータスで提供されています。
本稿では、現行のスタンダードなプラクティス、【2】-2の方式を用いて、ログとトレースの関連付けを紹介します。
ここでは、上記【2】-2の方式を採用し、ログフォワーダーとしてPromtailを、ログバックエンドとしてGrafana Lokiを用います。
後述する構築手順でも述べますが、Helmチャート「loki-stack」を用いることで、Grafanaダッシュボード、Promtail、Grafana Lokiを含めたツールセットを簡単にデプロイできます。
本稿で紹介する方法は、次の手順です。
Grafanaのダッシュボード上での上記ステップの遷移は後述します。
今回は、図中の【2】-2の方式を利用しましたが、全てのテレメトリーをOpenTelemetry Collectorに集約して処理する【1】の方式がOpenTelemetryでは推奨されています。しかし、2023年2月の原稿執筆時点ではOpenTelemetryのログ仕様は過渡期で、下表のようなステータスです。
概要 | ステータス |
---|---|
API | draft |
SDK | draft |
Protocol | stable |
ログデータモデルの仕様などを定めるProtocolのみstableで、APIとSDKはdraftです。従ってログインストルメンテーション用のAPI/SDKも、一部言語(Java、Pythonなど)のみexperimentalステータスで提供されている状況です。そのため、【1】の方式は時期尚早といえるでしょう。
OpenTelemetryのログデータモデルは下表の通りです。トレースIDやスパンIDのフィールドも用意されています。
Field Name | Description |
---|---|
Timestamp | イベントが発生した時刻 |
ObservedTimestamp | イベントが収集された時刻(Timestampより後の時刻) |
TraceId | トレースID |
SpanId | スパンID |
TraceFlags | W3Cで定義されるトレースフラグ |
SeverityText | ログレベル |
SeverityNumber | ログレベルを数字(優先度)で表したもの |
Body | ログメッセージ |
Resource | ログのソースを記述。Resourceで定義 |
InstrumentationScope | ログを生成したスコープを定義 |
Attributes | イベントに関するメタデータを定義 |
また【2】-1の方式は、OpenTelemetry Collectorのコンポーネント「Filelog Receiver」「Fluent Forward Receiver」を用います。いずれもbetaステータスの段階です。
上記のような理由で、本稿では安定して利用可能な【2】-2の方式を用いています。
ここでは、「どのようにアプリケーションログに対してトレースID、スパンIDを付与するか」を紹介します。
Go言語のサンプルアプリケーションで、トレースIDとスパンIDを構造化ログのフィールドに追加して標準出力します。トレース情報はコンテキストから取得します。下記のサンプルコードでスパン生成時に用いているtracerオブジェクトの設定方法などは前回記事を参照してください。
// スパンの生成とログ出力を行う関数 func LoggerAndCreateSpan(c *gin.Context, msg string) trace.Span { // スパンを生成する _, span := tracer.Start(c.Request.Context(), msg) // トレースIDとスパンIDを抽出する SpanId := span.SpanContext().SpanID().String() TraceId := span.SpanContext().TraceID().String() // ログライブラリの設定(本サンプルアプリでは、Go言語のログライブラリ「Zap」を利用) logger, err := zap.NewProduction() if err != nil { log.Fatal(err) } defer logger.Sync() // 出力する構造化ログの設定 logger.Info( // ログメッセージ zap.String("Body", msg), // スパンIDの設定 zap.ByteString("SpanId", []byte(span.SpanContext().SpanID().String())), // トレースIDの設定 zap.ByteString("TraceId", []byte(span.SpanContext().TraceID().String())), ) return span } func getSignup(c *gin.Context) { // スパン生成とログ出力 defer LoggerAndCreateSpan(c, "ユーザー登録画面の取得").End() generateHTML(c, nil, "signup", "layout", "signup", "public_navbar", "footer") }
このようにログを設定することで、以下のようにログフィールドにトレースIDとスパンIDを設定してログを出力でき、ログとトレースを関連付けることができます。ログとしては次のようなJSON形式で出力します。
{ # Zap で自動付与されるログフィールド "level": "info", "ts": 1676215284.5673957, "caller": "controllers/utils.go:102", # 手動で追加したログフィールド "Body": "ユーザー登録画面の取得", "SpanId": "96c9fe5a2b31f709", "TraceId": "3151c9f03ca6831bb8964dd78a53c2fb" }
「【1】ログライブラリを用いて、アプリケーションからOpenTelemetry Collectorにログ送信する」場合は、コラムで述べたOpenTelemetryで定められたデータモデルのフィールドにトレースIDとスパンIDがあるので、ログライブラリを用いてアプリケーション側でIDを設定します(言語によってはログライブラリ側で、自動的にトレースID、スパンIDをログフィールドにIDを付与してくれます)。
本稿で検証する「【2】ファイルやログフォワードツールを経由して、OpenTelemetry Collectorに送信する」場合でも、上記のようにログ出力の際にIDを設定する必要があり、今回は手動でフィールドを追加しています。
ここまではログとトレースを関連付ける方法を見てきましたが、ここからは同様にメトリクスにトレースIDを付与してトレースとメトリクスを関連付ける方法を紹介します。
ただ、全てのメトリクスをトレースなどのテレメトリーを関連付けることは難しく、またCPU使用率、メモリやディスク使用量といった特定のリクエストによらないメトリクスを特定のトレースのトレースIDで対応付けることは困難です。
そこで本稿では、OpenTelemetry Collectorで簡単に生成でき、トレースIDと関連付けることができる「スパンメトリクス」を使って、メトリクスとトレースを関連付ける方法を紹介します。
スパンメトリクスは分散トレーシングのスパンにおける情報を提供するメトリクスです。OpenTelemetry Collectorで収集したトレース情報から生成され、トレースごとに下記のメトリクスが作られます。
メトリクス | 種類 | 内容 |
---|---|---|
calls_total | Counter | トレースに含まれるスパンの数 |
latency_sum | Summary | トレースに含まれるスパンのレイテンシ総和(=トレースのレイテンシ) |
latency_bucket | Histogram | トレースのレイテンシ分布 |
スパンメトリクスは、OpenTelemetry Collectorのコンポーネント「Span Metrics Processor」を用いることで、特にアプリケーション側にメトリクス収集のためのインストルメンテーションをすることなくアプリケーションメトリクスを収集できます。
「latency_bucket」は収集した各トレースのレイテンシにおけるヒストグラムです。レイテンシ分布における平均値に最も近いトレースを「Exemplar」(エグザンプラー)といい、そのヒストグラムを代表するトレースとします。
スパンメトリクスのlatency_bucketにExemplarのトレースIDをひも付けて付与することで、トレースと関連付けることができます。
ExemplarのトレースIDのスパンメトリクスのひも付けは、OpenTelemetry CollectorのSpan Metrics Processorが行います。
Exemplarのトレース情報が追加されたlatency_bucketは次のような形式です。
traces_spanmetrics_latency_bucket{“le”=0.05} 1 traces_spanmetrics_latency_bucket{“le”=0.5} 3 traces_spanmetrics_latency_bucket{“le”=1} 4 # trace_id="043cd631811e373e4180a678c06b128e",span_id="cd122e457d2ca5b0" traces_spanmetrics_latency_bucket{“le”=INF} 5
bucketは、各メトリクスがヒストグラムの各区間に「le=xxx」で指定した値以下のレイテンシのトレースが何個あるかを示しています(詳細は連載第15回参照)。平均値に一番近いトレースの値がExemplarとして、ヒストグラムにその値が含まれる区間("le"=1の区間)に追加されます。
ここでは下記手順で、OpenTelemetry Collectorでスパンメトリクスを作成、メトリクスバックエンドとしてPrometheusを用います。
Grafanaのダッシュボード上における上記ステップの遷移は後述します。
テレメトリーをひも付ける理論が分かったところで基盤を構築します。本稿では前回構築した環境は利用せずに、一から環境を構築します。
次の流れでコンポーネントをデプロイします。
テレメトリーを関連付けるように設定してデプロイするコンポーネントもあるので、適宜解説します。
Observabilityツールをインストールする「observability namespace」とサンプルアプリケーションをデプロイする「todo namespace」を作成します。前回記事に沿って、環境を構築している場合は、前回作成したnamespaceを削除してください。
$ kubectl create ns observability $ kubectl create ns todo
最初に、OpenTelemetry Collectorデプロイに必要な、cert-managerとOpenTelemetry Operatorをデプロイします。
# cert-managerのデプロイ $ helm repo add jetstack https://charts.jetstack.io $ helm repo update $ helm install \ cert-manager jetstack/cert-manager \ --namespace observability \ --version v1.9.1 \ --set installCRDs=true \ --wait # OpenTelemetry Operatorデプロイ $ helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts $ helm repo update $ helm install \ otel-operator open-telemetry/opentelemetry-operator \ --namespace observability \ --version 0.20.4 \ --set installCRDs=true \ --wait # cert-manager と OpenTelemetry Operator 確認 $ kubectl get po -n observability | grep manager cert-manager-7b8d75c477-vdzsw 1/1 Running 0 6h49m cert-manager-cainjector-6cd8d7f84b-9vql7 1/1 Running 0 6h49m cert-manager-webhook-66fc85bd57-hrmz6 1/1 Running 0 6h49m opentelemetry-operator-controller-manager-7944958b76-6sf6j 2/2 Running 0 6h48m # OpenTelemetry Collectorデプロイ kubectl -n observability apply -f https://raw.githubusercontent.com/cloudnativecheetsheet/opentelemetry/main/02/otel-collector-config.yaml # OpenTelemetry Collector確認 $ kubectl get po -n observability | grep collector sample-collector-74dcc5ff88-7pl7b 1/1 Running 0 16m
OpenTelemetry Collectorのconfigファイルは「otel-collector-config.yaml」です。下表のコンポーネントを有効にしています。
テレメトリー | Receiver | Processor | Exporter | 設定 |
---|---|---|---|---|
トレース | otlp | spanmetricsprocessor | otlp | Grafana Tempoにトレース送信 |
メトリクス | --- | --- | prometheusremotewrite | Prometheusにメトリクス送信(RemoteWrite) |
Receiverは、OpenTelemetry Collectorでテレメトリーを受け取るコンポーネントです。Processorは、ラベル付与やフィルタリング、サンプリングなどテレメトリーに対して処理するコンポーネントです。Exporterは、テレメトリーをバックエンドに送信するコンポーネントです。
今回利用しているスパンメトリクスは、トレース情報からProcessorによって生成されるので、メトリクスを受け取るReceiverは何も設定されませんが、Processorによって生成されたメトリクスをバックエンド(Prometheus)に送る必要があるのでExporterはPrometheus Remote Write Exporterを利用しています。
なお、Logging Exporterを利用して、各テレメトリーをOpenTelemetry Collectorのログとして出力できます。デバッグやOpenTelemetry Collectorの挙動確認時に便利です。ただし、大量のログが出力されるの運用時には留意が必要です。
Prometheusのメトリクス収集方式としてプル型とプッシュ型があり、本稿では、プッシュ型でメトリクスをPrometheusに送信できる「Prometheus Remote Write」機能を利用します。
プル型のexporterはPrometheus Exporterとして用意されています。
アプリケーションからOTLP(OpenTelemetry Protocol)で送信されたメトリクスや、OpenTelemetry CollectorのProcessorで生成されたメトリクスは、OpenTelemetry CollectorのRemoteWrite ExporterからPrometheusサーバに送信されます。
Grafana Loki、Grafana、Promtailをデプロイします。これらは前述のloki-stackに同梱されていて、一緒にデプロイできます。下記の手順でデプロイします。
# Grafana Loki/Grafana/Promtailデプロイ $ helm repo add grafana https://grafana.github.io/helm-charts $ helm repo update $ helm upgrade --install loki --namespace=observability grafana/loki-stack \ --values=https://raw.githubusercontent.com/cloudnativecheetsheet/opentelemetry/main/02/loki-stack-values.yaml # Grafana Loki/Grafana/Promtail確認 $ kubectl get po -n observability | grep loki loki-0 1/1 Running 0 3m35s loki-grafana-9d68b6b77-jsrrg 2/2 Running 0 3m35s loki-promtail-bvf5g 1/1 Running 0 3m35s loki-promtail-lclrc 1/1 Running 0 3m35s loki-promtail-vn2fr 1/1 Running 0 3m35s
各コンポーネントの設定は「loki-stack-values.yaml」にあります。
Promtailの設定は、デフォルトの設定から、下記のように変更しています。
promtail: enabled: true config: lokiAddress: http://loki.observability.svc.cluster.local:3100/loki/api/v1/push snippets: pipelineStages: - docker: {} - json: expressions: trace_id: trace_id span_id: span_id - labels: trace_id: span_id:
「promtail.config.lokiAddresss」にGrafana Lokiの接続先を指定します。「promtail.config.snippets」に取り込んだログの「trace_id」「span_id」フィールドを、Lokiのラベルとして使用することを宣言しています。なお上記の設定は、今回のサンプルの場合です。ラベルの設定はログの出力形式によって異なるので注意してください。
本稿では、Promtailを用いてログ収集を行っていますが、OpenTelemetry CollectorのFilelog Receiverを利用することも可能です。
Filelog Receiverを用いることでPromtail同様にログファイルを取り込むことができます。収集したログはOpenTelemetry Collectorのパイプラインでログへの追加処理(属性情報の追加やフィルタリングなど)、エクスポーターを経由してログコレクターに送信されます。
KubernetesでFilelog Receiverを利用する場合、OpenTelemetry Collector Helmチャートを利用すると便利です。Podのログを収集する設定を簡易化し、ログにKubernetesの情報(Pod名、namespace名、クラスタ名など)のラベルが自動的に付与されます。
OpenTelemetry Colletor Helmチャートには、「DaemonSet」「Deployments」「StatefulSet」の3つのモードがあり、各ノードのログファイル取り込む場合、DaemonSetモードでデプロイする必要があります。また、ログコレクタの設定や属性の取得の設定などが必要ですが、詳細は、「Configuration for Kubernetes container logs」「Configuration for Kubernetes attributes processor」をご覧ください。
Grafana Tempoをデプロイします。
# Grafana Tempoのデプロイ $ helm install \ tempo-distributed grafana/tempo-distributed \ -n observability \ --version 0.26.8 \ --set traces.otlp.grpc.enabled=true \ --set search.enabled=true \ --wait # Grafana Tempo確認 $ kubectl get po -n observability | grep tempo tempo-distributed-compactor-7d7b475d8f-gsj4g 1/1 Running 0 92s tempo-distributed-distributor-7c9bcc855c-s76nb 1/1 Running 0 92s tempo-distributed-ingester-0 1/1 Running 0 92s tempo-distributed-ingester-1 1/1 Running 0 92s tempo-distributed-ingester-2 1/1 Running 0 91s tempo-distributed-memcached-0 1/1 Running 0 92s tempo-distributed-querier-6599c84b5d-lggdp 1/1 Running 0 92s tempo-distributed-query-frontend-56b5f7fbc8-dtkwp 1/1 Running 0 92s
Grafana Tempoは前回記事と同様の構成でデプロイしました。「traces.otlp.grpc.enabled」を有効化してOTLPポートを開いています(デフォルトでは無効)。「search.enabled」はトレース情報のサーチ機能です。取得したトレースを一覧表示できて便利なので、有効化してトレース確認時に使用します。
Prometheusをデプロイします。
# Prometheusのデプロイ $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts $ helm repo update $ helm install kube-prometheus-stack \ prometheus-community/kube-prometheus-stack \ -n observability \ --values=https://raw.githubusercontent.com/cloudnativecheetsheet/opentelemetry/main/02/kube-prometheus-stack-values.yaml \ --wait # Prometheus確認 $ kubectl get po -w -n observability | grep prometheus kube-prometheus-stack-operator-68689b4554-hzvk7 1/1 Running 0 47s prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 45s
Helmチャートは「kube-prometheus-stack」を用いました。幾つかコンポーネントが同梱されていますが、ここではPrometheusのみを有効化して他のツールは「enabled=false」としています。
また「prometheus.prometheusSpec.enableFeatures」に「remote-write-receiver」と「exemplar-storage」を設定しています(デフォルトでは非設定)。この設定によって、PrometheusへのRemote Writeと、PrometheusでトレースIDが付与されたメトリクスを収集できるようになります。
最後に、OpenTelemetryでインストルメンテーションした、Go言語のサンプルアプリケーション(Todoアプリ)をデプロイします。ビルド済みのイメージを用意しているので、下記のマニフェストをデプロイするだけで使えます。
# サンプルアプリケーションデプロイ $ kubectl -n todo apply -f https://raw.githubusercontent.com/cloudnativecheetsheet/opentelemetry/main/02/application.yaml # サンプルアプリケーション確認 $ kubectl get po -n todo NAME READY STATUS RESTARTS AGE postgresql-79969bf55-h5wtb 1/1 Running 0 44m todoapi-7dc6cb8c8c-mvwzq 1/1 Running 0 44m todobff-69f559468f-cxhg2 1/1 Running 0 44m userapi-6db546df8d-vpw4j 1/1 Running 0 44m
なお、サンプルアプリケーションのソースコードはGitHubのリポジトリに公開しているので、興味がある方はご覧ください。
最後にサンプルアプリケーションを動かしながら、Grafana上で“関連付けられた”テレメトリーを確認します。
Grafanaダッシュボード上でテレメトリー間を遷移するために、各テレメトリーに付与しているトレースIDを関連付ける必要があります。ログのトレースIDやメトリクス(スパンメトリクス)のトレースIDと分散トレーシングのトレースIDと関連付けることで、ダッシュボード上でトレースIDを介して関連付いたテレメトリーを簡単に確認できます。
トレースIDの関連付けのイメージは下図の通りです。
ログとトレースを関連付けます。Grafanaへのログイン方法は前回記事で紹介した方法と同じです。
最初にGrafana Tempoのデータソースを追加し、設定します。「Data sources」で「Tempo」を選択します。
次に、Tempoを設定します。
【1】のエンドポイント指定では、「http://tempo-distributed-query-frontend:3100」を指定します。【2】の「Save & test」を押して、「Data source is working」のチェックマークが表示されたら設定終了です。
続いて、Lokiを設定します。
【1】のエンドポイント指定では、「http://loki:3100」を指定し、【2】のDerived fieldsでログフィールドのtrace_idと、TempoのトレースIDをひも付けます。これによって、ログフィールド「"trace_id"」に設定されているトレースIDでTempoのトレースを関連付け、Grafanaダッシュボード上でテレメトリー間を遷移できます。
【3】「Save & test」を押して、「Data source connected and labels found」のチェックマークが表示されたら設定終了です。「Explore」を押してログを探索してみましょう。
ExploreではLokiに対してアドホックなクエリを投げることができ、ログ解析を簡易化できます。
ここでは、【1】「{app="todobff"}」でサンプルアプリケーションのログを抽出しています。
ログを見ると、アプリ内で付与した属性情報が載っていることが分かります。trace_idやspan_idも付与されています。trace_idの横に【3】「tempo」のボタンが用意されています。先ほど、Derived fieldsにtrace_idを設定したからです。こちらを押下するとログに関連付いたトレースIDのトレースが、右側のペインに表示されます。
ログに付与されたトレースIDを介して、Grafanaダッシュボード上で容易にトレースに遷移できました。テレメトリーをトレースIDによって関連付けることによる恩恵です。
メトリクス(スパンメトリクス)とトレースを関連付けます。先ほどと同様に、Prometheusのデータソースを追加し、設定します。
ExploreでPrometheusに対してアドホッククエリを投げてみましょう。検索に使うメトリクスは次の通りです。
histogram_quantile(0.90, sum(rate(latency_bucket[30s])) by (le) )
これによって、「単位時間当たりのトレースにおけるレイテンシの、90%が収まるレイテンシの値」が求まります。言い換えると、例えばビジネス目標が「リクエストの90%が200ミリ秒以内にレスポンスを返却する」といった場合、このメトリクスが200ミリ秒を超えたときにアラートを発するような形で使えるかもしれません。
メトリクスを指定して、【2】クエリを実行するとメトリクスが表示されます。ひし形(◇)のプロットが、Exemplarが付与された(=トレースIDと関連付いた)メトリクスです。
ひし形のプロットをマウスオーバーすると、Exemplarの情報が表示されます。このメトリクスを生成するのに使用されたトレース情報です。トレースIDやスパンIDなどがラベルと共に付与されています。トレースIDにはTempoへの動線が用意されており、「Query with Tempo-ITMedia」を押すと、先ほどのLokiのときと同様に右側に分散トレーシングのペインが表示されます。
先ほどと同様のカラクリで、Exemplarのtrace_idに格納されたトレースIDでTempoをクエリしている形です。このようにGrafanaダッシュボード上で、メトリクスに付与されたトレースIDを介してトレースに遷移できました。
今回は、テレメトリーにトレースIDを付与することで“関連付け”し、それぞれのテレメトリーの間に意味を与えました。さらに、テレメトリーを関連付ける意義の一例として、Grafanaダッシュボード上でテレメトリー間の遷移、例えば「ログからトレース」「メトリクスからトレース」といったテレメトリーの探索やトラブルシューティングを容易にできることを紹介しました。
複雑で動的に変化するクラウドネイティブ環境では、従来のモニタリングとは異なる視点や切り口でテレメトリーを追跡できる可観測性(Observability)が非常に重要です。本稿で紹介した「テレメトリー間の関連性を保ち続ける(見失わない)こと」はObservabilityにとって重要な要素の一つです。
Copyright © ITmedia, Inc. All Rights Reserved.