OpenTelemetry について調べてみた
今後の仕事で必須になってきそうだったので、OpenTelemetry について調べていた。
OpenTelemetryをざっくり言うと、メトリクス(CPU利用率など)、トレース、ログの3種類の監視情報の取得、加工、送信仕様を標準化したものだ。
従来であれば、メトリクスはOS付属の perfmon (Performance Monitor) や sar (System Activity Report) で取得、ログはファイルに出力、トレースはログファイルのログレベルとして定義、というのが一般的だったと思うがクラウド利用が一般化するに従い、各クラウド付属の CloudWatch や Cloud Monitoring、専用サービスである DataDog、New Relic、Splunk、DynaTrace といったツールで一元管理することが一般的になってきた。
これらのツールの仕様はベンダー依存であるため、製品によってCPU利用率を表す項目がまちまちだったり、相互の接続性に制限が存在したが、OpenTelemetry を使うことでベンダー非依存にできることが期待される。
まず、最近出たばかりの「入門 OpenTelemetry ―現代的なオブザーバビリティシステムの構築と運用」を読んだのだけど、仕様策定者が書いた本で設計の意図はわかったものの、実務的な情報が少なくて、単になんか複雑でよくわからん、という感想しか残らなかった。
OpenTelemetry がなぜ複雑でわかりにくいのかと言えば、仕様上、プログラミング言語×接続元ツール×接続先ツールの組み合わせが発生せざるを得ず、単に標準仕様を定めました、というだけでは済まないからだろう。その結果として Collector という概念が出てくるがこれが最初はわかりにくい。
さらにややこしいのは各ツールでのサポートが現状まちまちで、例えば Node.js 用のログインターフェイスはいまだ開発中だったり、CloudWatch の OpenTelemetry サポートはトレースとログだけでメトリクスが含まれなかったり、という状況にある。これは時間が経てば解決する問題ではあるが現時点で実装する際には問題となる。
OpenTelemetry の理解を容易にするために順を追って説明する。まず、「Exporter」と呼ばれる送信側と「Reciever」と呼ばれる受信側がある。ようはログなどの出力側(アプリケーションなど)とログなどを送り付けられる側(監視ツールなど)のことだ。実際には「Exporter」や「Reciever」には複数あるのだが、ここではOpenTelemetryの標準プロトコル「OTLP」に従って通信することだけを考える。すると次のようになる。
[アプリケーション] → [Exporter(OTLP)] → (ネットワーク) → [Reciever(OTLP)] → [監視ツール]
一番簡単なパターンだとこれだけで完結する。Exporter として標準で用意されている各言語用向けのSDKを使うと OTLP に従って Reciever にログなどを送り付ければよい。OTLPエンドポイントを提供している監視ツールであれば、これだけで良い。
しかしながら監視ツール側がOTLPエンドポイントを提供しているとは限らないし、OTLPエンドポイントだけでは設定が不足する場合がある(例えば、認証や送信制御)ため、Exporter が出力した OTLP を独自のプロトコルに変換する必要が出てくる。そこで出てくるのが Collector である。
[アプリケーション] → [Exporter(OTLP)] → (ネットワーク) → [Collector(OTLP to 監視ツール独自)] → (ネットワーク) → [監視ツール]
Collector はようはプラグインだと思えばよいのだが、ややこしいのがこのCollector 自体が。Reciever + Processor + Exporter としても表現できカスタマイズできるよう抽象化されている点にある。そして、このProcessorによる加工処理(例えばpushのバッチ化やリトライといった通信制御など)を生かすために Collector を使うことが推奨されている。もちろん、アプリケーションと Exporter の間にProcessor を入れることは可能なのだが、それを行うとアプリケーション側で設定を入れねばならず不要な依存性が発生してしまうから避ける方が望ましいという考えなのだろう。
例えば AWS Distro for OpenTelemetry は、OTLPトレースを X-Ray、OTLPログやメトリクスをCloudWatchに変換する Collector となっている(すなわち Reciever が OTLP、Exporter が AWS独自)。これをサイドカーとして実行することでアプリケーション側は単に OTLP Exporter で出力すればいいという状態にできる。各言語向けのSDKはデフォルトで localhost:4317 にて OTLP/gRPC が localhost:4318 にて OTLP/HTTP で受信できる Collector が存在することを前提に起動するようになっているので、その約束に従っている限りアプリケーション側は特別な対応が不要ということなる。
ExporterだけでなくReciever も抽象化されている。例えば Prometheus 形式で受信したければ Prometheus Receiver を使うこともできるし、Kubernates の pod などの情報を得たければ、Kubeletstats Receiver を使うことができる。
現状はなかなか整理されておらずドキュメントも混沌とした状況にあるが、今後のスタンダードになると思われるので、継続して調査しておきたい。
