Scala + Play Framework の環境に分散トレーシングを導入する(したい)
Scala + Play Framework の環境で分散トレーシングを導入したくなったので色々調べたり実験しました。(結論から言うと、まだうまくいっていません…。)
分散トレーシングって?なんで使いたいの?
今回、僕が導入したいシステム(サーバサイドアプリケーション)はマイクロサービスアーキテクチャではないのですが、APIのレスポンスタイム向上のために分散トレーシングシステムを入れたくなりました。 もちろん本当は「分散」トレーシングシステムである必要はなく、単純に グラフィカルに 処理のボトルネックを見たいだけです。
例えば、並行に処理している場合、ボトルネックを分析するのがログ等のテキストだと難しいことがあります。
以下のような処理があったとします。
それぞれの処理のログがあったとして、すぐにボトルネックを見つけることはできるでしょうか?
A: 100ms B: 50ms C: 120ms D: 10ms E: 45ms
答えですが、ボトルネックは AとE です。次のように図にすると明らかです。
これが現実のAPIだった場合、AとE以外の処理の高速化をいくら試みても、全くの見当違いでAPIレスポンスタイムは向上しないことになります。
それでもまだ今回はまず図があったため数字さえ書き込めばボトルネック分析は容易ですが、現実のアプリケーションの場合、そもそも図に正確に起こすところが大変になる場合もあるでしょう。
分散トレーシングでは、分散トレーシングのための仕組みをアプリケーションに取り込むことで、処理の流れを上図のようにグラフィカルに見ることができます。
分散トレーシングを実現するミドルウェア
たくさんありますが、今回は以下のアプリケーションを試してみることにしました。
Jaeger
- Uber Technologies が作っているやつ。
- バックエンドのデータストアとして Cassandra, Elasticsearch が利用可能。
- OpenTracing という規格に対応
Elastic APM
- Elastic が作っているやつ
- 当然バックエンドは Elasticsearch
- OpenTracing という規格に対応
どのように処理を記録していくのか?
https://www.jaegertracing.io/docs/1.16/architecture/ から引用
処理の単位を Span
と呼び、 Span
は親を持つことができます。
Span
の塊を Trace
と呼びます。
「分散」トレーシングにおいては別のマイクロサービスに対しコンテキストを渡す…などの概念がありますが、今回はモノリシックアプリケーション内でのトレーシングを目標としているので、割愛します。
また、使うミドルウェアによって多少言葉は異なりますが、大まかには同じです。
次回以降、実装例を紹介します。