TT Lab
はじめる
学ぶ 学習パス コース

分散トレーシングが切れる場所

ダッシュボードで見た山をトレースで探し直すには

TT Labで続きを見る

一言でいうと

メトリクスとトレースが同じ名前・同じ値の属性を持ち、サンプリング率がスパンに書かれていて初めて、ダッシュボードで見たピークをトレースで再び見つけられます。

なぜ必要なのか

障害のふりかえりで出た要望は、シンプルでした。「エラー率パネルが9時40分に跳ね上がっているので、そのときの失敗したリクエストを1つだけ開いてみよう」。ところが、開けませんでした。メトリクスにはhandler="/order/:id"というラベルが付いていて、スパンにはhttp.target="/order/8821"が付いていました。名前も違い、値も違っていました。2つをつなぐものが人の頭の中にしかなく、ピークからトレースへ行く道がなかったのです。

さらに悪いことが、そのあとにありました。誰かが「スパンで数えればいいのでは」と言ってダンプからエラー率を計算し、29%という数字を持ってきました。メトリクスは同じ区間で7.5%を指していました。かなりあとで原因がわかりました。そのサービスは、エラーになったリクエストはすべて残し、成功したリクエストは5件に1件だけ残していたのです。サンプルがエラー側に偏っているので、そのサンプルで数えた割合が正しいはずがありませんでした。

どう動くのか

2つのシグナルを対応づけるには、3つのものが必要です。

1つ目、共通属性が同じ名前・同じ値で両側にある必要があります。メトリクスはカーディナリティの都合でアドレスをそのまま使えないため、登録されたルートテンプレートを使います。トレースは元のアドレスをそのまま入れてもかまいませんが、対応づけ用の属性だけはメトリクスと同じ値でなければなりません。そのため、スパンには2つを一緒に置きます。対応づけ用のhttp.routeと、調査用の元のアドレスです。名前は、HTTPスパンのセマンティックコンベンションとHTTPメトリクスのセマンティックコンベンションが同じhttp.routeにそろえてあるので、自分で名前を付けずにそのまま使うのがよいです。

2つ目、割合はスパンで数えてはいけません。メトリクスはすべてのリクエストを数えますが、トレースはサンプルだけを残します。サンプルが均等に選ばれていたとしても、スパンで数えた個数は何分の1かであり、サンプルがエラー側に偏っていれば、割合そのものが丸ごと間違います。ラボで、同じデータから7.5%と29.0%を自分で作ってみます。

3つ目、サンプリング確率をスパンに書いておいて初めて元に戻せます。スパン1つが何件を代表するかは、そのスパンが残る確率の逆数です。確率1/5で残ったスパンは5件を、確率1で残ったスパンは1件を代表します。その重みを足せば、個数と割合がおおむね戻ってきます。この計算を標準ではadjusted countと呼び、確率サンプリングの仕様に定義があります。

元に戻せないものも、はっきり知っておく必要があります。サンプルに1件も入ってこなかった組み合わせは、0のまま残ります。まれに起きるエラーがダッシュボードから丸ごと消えるのは、ここで起きます。パーセンタイルも戻りません。重みは個数を直しますが、分布の形は直せず、特に裾はサンプルが少ないほど大きく揺れます。そのため、個数と割合はメトリクスから読み、トレースは1つの例を探すために使うのが正しいです。

メトリクスからトレースへ渡る橋は、その例をあらかじめ選んでおく作業です。区間ごとに代表1件のtrace_idを残しておけば、パネルからそのトレースへ直接行けます。この方式の標準名がexemplarで、エクスポジション形式の規格はPrometheusのエクスポジション形式のドキュメントとOpenTelemetryメトリクスのデータモデルにあります。ただしこのラボ環境では、exemplarを実際に保存したり照会したりできません。このイメージにはPrometheusがそもそもなく、観測ラボのPodのPrometheusも、exemplarの保存機能をオフにして起動しています。そのため、ここでは代表を選ぶ作業と、その表を作るところまでを行い、メトリクスはエクスポジション形式のテキストファイルとして扱います。

限界もそのまま書いておきます。代表は区間ごとに1件だけなので、普通のリクエストへ渡ることはできず、サンプルから抜けたリクエストは、どれだけ遅くても代表にはなれません。

ここで扱わないことも、はっきりさせておきます。メトリクスSDKの累積とデルタを選び、ビューを設定する作業は、メトリクスの時間性のモジュールの役割であり、どの事象をSLIにするかを決める作業は、SLIモジュールの役割です。このモジュールが行うのは、その2つの間です。2つのシグナルを対応づけられるように計装する作業であり、成果物は、メトリクスの設定でもSLIの定義でもなく、属性ルールのファイルと、2つのシグナルを突き合わせる検査プログラムです。

現場での姿

最もよくある事故は、ルートの値がずれることです。メトリクス側はフレームワークが自動でルートテンプレートを入れてくれるのに、トレース側は手で計装するときにアドレスをそのまま入れてしまうことが多いです。そうすると、系列9本のメトリクスと、30個を超えるスパンのグループが向き合うことになり、対応づける方法がありません。このずれは、ダッシュボードが問題なさそうに見えるため、障害が起きるまで誰も気づきません。

2つ目は、エラーをすべて残すサンプリングポリシーです。良い意図で入れるのですが、そのサンプルで割合を数える人が必ず現れます。サンプリング確率をスパンに書いておけば、少なくとも元に戻す道ができ、書いておかなければ、そのデータは割合の計算にはもう一生使えません。

次のラボですること

まず、スパンダンプだけで、リクエスト数・エラー数・レイテンシ分布を数えてみます。次に、メトリクス側が出力するエクスポジション形式のファイルと比べて、名前と値がどうずれているかを表にし、計装を直して、2つのシグナルが同じキーでつながるようにします。続けて、サンプラーを切り替えながら、同じデータから異なるエラー率が出る様子を自分で作り、サンプリング確率の逆数で補正して元に戻したあと、補正でも直せないものを書きます。最後に、区間ごとに代表トレースを選ぶブリッジを作り、ルールをファイルに固めて、2つ目のサービスに適用し、2つのシグナルが合っているかを検査プログラムで確認します。