最初に断っておきますと、OpenTelemetry を良く知っていたり真面目に調査しようという人が読むべき内容はここにはありません。 公式ドキュメントなりをご参照ください。これは最近 OpenTelemetry を使いだした一般人の感想記事です。
さて、いけてる Web 開発者、特にバックエンド開発者の方はオブザーバビリティという言葉は聞き及んでいるかと思います。 なかでもオブザーバビリティ三種の神器と言われている(?)ログ、メトリクス、分散トレーシングをどう実装するか頭を悩ませているかもしれません。
頭を悩ませてきた、あるいは頭を悩ませている理由の一つは、これらを実装するときに特定の実装向けになりがちであったためです。
メトリクスであれば最近は Prometheus 向けに /metrics
エンドポイントとして提供する実装が多いといった話です。しかしながら、
あらゆる人が Prometheus を使うわけでもないので、汎用的なソフトウェアを書く場合に悩ましかったりしたわけです。
OpenTelemetry は、逆説的に特定の実装を排して、SDK とプロトコルだけを規定することでどんなソフトウェアにも組み込んで良い、 一度組み込んだらメトリクスサーバーやトレーシングサーバーをいつでも変更可能になるよという CNCF のプロジェクトです。まだ 一部の機能、例えば Go SDK でログが未実装といったところはありますが、トレーシングやメトリクスは十分インストルメント可能です。
そんな噂を聞いて、新規のサービス開発でこれからやるなら OpenTelemetry でインストルメントしていくのかなと思いつらつらやってました。 以下、調べたり学んだりしたことと、現状できていることです。正確性は全然担保しないので、使うときはちゃんと調べてくださいね。
基礎知識
インストルメント
日本語では計装と書いたりもするのかもしれない。メトリクスやトレースやログをプログラムのコード中に仕込むこと。 この仕込みコードが特定サーバー向けだと辛いなっていうのが OpenTelemetry やりたい動機。
OpenTelemetry
プロジェクト名。メトリクスやトレースやログをプログラムから出力するための SDK や、ネットワークプロトコルを規定している。
OTLP
OpenTelemetry のネットワークプロトコルの名前。OTLP に対応しているサーバーなら直接メトリクスやトレースを受け取れる。 そうでない場合も、Collector や Exporter が各種揃っていて非常に幅広いサーバーに対応できる。
Collector
OpenTelemetry でインストルメントしたプログラムはもちろん、それ以外(例えば OpenCensus とか)で実装したプログラムからも 幅広くメトリクスやトレースを受け取り、必要に応じて加工して、どこか別のサーバーに出力してくれる中間プロクシ。 otelcol とか otel-collector とか呼ばれたりもする。後述しますが、実運用では必ず立てるべき。
Exporter
各種サーバーに通信するためのプラグインみたいな。Collector にも組み込めるのでインストルメントするプログラム本体に組み込む ことはあまりないんじゃないかしら。
Head/tail sampling
分散トレーシングでは、大半の成功リクエストは調べる価値がない(sample する価値がない)ということで切り捨てたくなる。 どのリクエストを sample するかの決め方に head sampling と tail sampling があり、簡単に言えば、head sampling はリクエスト を追跡開始する時点(多くの場合ロードバランサーとか)で sample するかどうか決めてしまう(多くの場合ランダムサンプリング) もので、tail sampling はリクエストが完了する時点で、エラーなら必ずサンプリングするみたいに決めるやり方。
良くある使い方
Collector を立てる
Collector の立て方にもパターンがいくつかあって、各プログラムに付随する(Kubernetes ならサイドカーコンテナ)やり方と、 外部に立ててロードバランスするようなやり方があります。cf. https://opentelemetry.io/docs/collector/deployment/
プログラムにインストルメントする
この時、Collector のエンドポイント指定は環境変数とかで可変にしておくと、上述のデプロイパターンの違いに対応できます。 やり方は言語毎に違うので、公式ドキュメントを参照してください。
Collector の設定ファイルで好きなサーバーに書き出す
Prometheus や Google のマネージドサービスや Jaeger など各種サーバーに書き出すことができます。
うちのいまのところ
私調査により、80% 以上のケースで tail sampling を実施しているそうです。 なので、うちも tail sampling することにしました。OpenTelemetry の場合、良くあるのは Collector を二段構えで構成するものです。
- 一段目: trace ID で二段目に振り分ける。メトリクスとかはここから直接 export していい。
- 二段目: 同一の trace ID のトレースを受け取り、tail sampling を指定されたルールで行う。
なので、サイドカーにはしていません。Go SDK がログには対応してないので、現状ログは stdout/err に流しています。 うちのトレースサーバーは JSON ログで特定の attribute を含めるとトレースに対応させることができるので、そうやって外部的に結合させています。
感想
という感じで使っていますが、OpenTelemetry のサイトは必要に応じてチラ見しているだけでやってきてしまいました。 実装例が充実していたり、OpenCensus とブリッジもできたりとあれこれ気が利いていて頑張らなくても使えてしまうのが素晴らしいなと思います。
以上