Cloud Runのトレースサンプリング: OpenTelemetryとb3の活用
はじめに
前回、Cloud RunのトレースのサンプリングレートはGoogle Cloudに任せようで以下のように書きました。
基本はGoogle Cloudにサンプリングをまかせ、つぶさに観察したいリクエストは強制的にトレースするのが良さそうです。
あるいはX-Cloud-Trace-ContextというGoogle Cloudの仕様に乗っかりたくない場合は、traceparentではなくb3を用いて自前で構築したオブザーバビリティバックエンドへエクスポートする
OpenTelemetry(以下OTel)がコントロールする前にGoogle Cloudがtraceparent
に介入してtrace_flags
を決定するのでサンプリングレートを自分たちでフルコントロールするのは難しいという話ですが、今回はOTel、b3
、Grafana Tempo
を使ってCloud Runへデプロイしたアプリケーションのトレースのサンプリングレートを自由に変えられるか試してみました。
もしGoogle Cloudの仕様から解放されたいと感じた時に役に立つ内容だと思います。
構成
今回の構成です。
コードは前回の記事と同じものをベースにしています。
Cloud Run
前回と同じくserver1とserver2の構成です。
server1のエンドポイントへリクエストするとserver2へリクエストするようにしています。
トレースバックエンド
Grafana Tempoを使いました。
無料プランでもクレカ登録が不要だったり、トレース/メトリクス/ログの容量が相当量あったりと充実しています。
OTel Collector
今回はトレースだけエクスポートするので、以下の設定でCloud Runへデプロイしました。
ちなみにサイドカーではないです。
receivers:
otlp:
protocols:
http:
processors:
batch:
exporters:
otlp:
endpoint: 'Grafana TempoのURL:443'
headers:
authorization: Basic <base64 data>
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [otlp]
How to send traces to Grafana Cloud's Tempo service with OpenTelemetry Collectorにauthorization
は以下の出力を貼り付ける例が記載されていますが、そのままリポジトリへpushしないよう注意です。
$ echo -n "<your user id>:<your api key>" | base64
OTel SDKの設定
traceparent
はGoogle Cloudがハンドルを握っているのでb3
を使います。
環境変数OTEL_PROPAGATORS
をb3
に設定するか、SDKへ明示的に定義するなら以下のようにします。
import { B3Propagator } from '@opentelemetry/propagator-b3'
export const openTelemetrySDK = new NodeSDK({
// ... SDKの設定
textMapPropagator: new B3Propagator(),
})
https://<Cloud Runの公開URL>/1
へリクエストして結果を確認します。
検証結果
HTTPヘッダーのtraceparent
, x-cloud-trace-context
, b3
は以下のようになりました。
traceparent
とx-cloud-trace-context
はGoogle Cloudの仕様でリクエストに自動付与されるので、/1のリクエストのHTTPヘッダーにすでに存在しますがb3
はありません。
これは通常、最初のリクエストのHTTPヘッダーにはトレース情報が存在しないからだと思います。
サンプリングのレートも異なり、b3ではX-B3-Sampled
が1と全てがサンプリングされています。
Grafana Tempoにも全て送られていました。
次にOTEL_TRACES_SAMPLER
とOTEL_TRACES_SAMPLER_ARG
をCloud Runの環境変数へ定義してサンプリングの変化を見てみます。サンプリング確率を0.2にしました。取りうるレンジは0~1なので0.2はおそらく20%です。
結果は以下のようにランダムにサンプリングされました。
always_off
へ変更すると全くサンプリングされなかったので、Google Cloudの仕様をかいくぐって期待通りにレートをコントロールできることがわかりました。
おわりに
サンプリングの主導権を握りたいならGoogle Cloudが介入しないかつOTelが公式にサポートしているプロパゲーターb3
を使うと良いということがわかりましたが、一方でGoogle Cloudの仕様に乗っかることのメリットはあるので、自由の代償として知っておきたいところです。
詳しくはヘンリーさんの事例から学ぶクラウドへのOpenTelemetry導入のハマりどころに書いてありとても参考になるのでぜひご覧ください。
私はCloud Loggingの絞り込み機能をよく使うので恩恵を受けようと思っていますが、自由になれる方法が分かったことは今回の収穫でした。自由と言っても結局何かのお世話にならないと生きていけないのですが。
余談:Cloud RunにとってOpenTelemetryを使う意義
OTelを導入しなくてもCloud Runへのリクエストは自動でトレースが生成されてCloud Traceで表示できる[1]ので、最初は導入意義がよくわかりませんでした。
attributesを自由に追加できるから?と思ったのですが、Cloud Trace APIでトレースラベルを使えばできる[2]ようなのでますますわからなくなりました。
今回の検証で、トレースをよしなにしてくれるというところに導入する意義があると思うに至りました。
試しにOTel無効の状態でデプロイしてhttps://<Cloud Runの公開URL>/1
へリクエストすると、一連のリクエストにもかかわらず別々のトレースIDが付与されました。
実はOTel + b3
でも同じことになりこちらの理由はよくわからず、おそらくGoogle Cloudはb3に介入しないからなのかもしれませんが、Propagatorがtraceparent
or x-cloud-trace-context
の場合は同じトレースIDになります。
traceparent
の場合
x-cloud-trace-context
の場合
一連のリクエストを同じトレースIDにするのはおそらくOTelがよしなにやってくれていて、だからこそCloud TraceでOpenTelemetryの使用を推奨しているのかなと思いました。[3][4]
Cloud Trace では、OpenTelemetry の使用をおすすめします。
OpenTelemetry ライブラリは、対応する Trace API の複雑さの一部を隠蔽しているため、Cloud Trace クライアント ライブラリよりも簡単に使用できます。
参考にさせていただいた記事
- 事例から学ぶクラウドへのOpenTelemetry導入のハマりどころ - 株式会社ヘンリー エンジニアブログ
- Vol. 04 Cloud RunでCloud Trace以外のAPMを使う場合の一工夫 - Sansan Tech Blog
Discussion