ましめも

技術系メモ

Scala + Play Framework の環境に分散トレーシングを導入する(したい)

Scala + Play Framework の環境で分散トレーシングを導入したくなったので色々調べたり実験しました。(結論から言うと、まだうまくいっていません…。)

分散トレーシングって?なんで使いたいの?

今回、僕が導入したいシステム(サーバサイドアプリケーション)はマイクロサービスアーキテクチャではないのですが、APIのレスポンスタイム向上のために分散トレーシングシステムを入れたくなりました。 もちろん本当は「分散」トレーシングシステムである必要はなく、単純に グラフィカルに 処理のボトルネックを見たいだけです。

例えば、並行に処理している場合、ボトルネックを分析するのがログ等のテキストだと難しいことがあります。

以下のような処理があったとします。 f:id:mashijp:20191228150054p:plain

それぞれの処理のログがあったとして、すぐにボトルネックを見つけることはできるでしょうか?

A: 100ms
B: 50ms
C: 120ms
D: 10ms
E: 45ms

答えですが、ボトルネックAとE です。次のように図にすると明らかです。

f:id:mashijp:20191228151016p:plain

これが現実のAPIだった場合、AとE以外の処理の高速化をいくら試みても、全くの見当違いでAPIレスポンスタイムは向上しないことになります。

それでもまだ今回はまず図があったため数字さえ書き込めばボトルネック分析は容易ですが、現実のアプリケーションの場合、そもそも図に正確に起こすところが大変になる場合もあるでしょう。

分散トレーシングでは、分散トレーシングのための仕組みをアプリケーションに取り込むことで、処理の流れを上図のようにグラフィカルに見ることができます。

分散トレーシングを実現するミドルウェア

たくさんありますが、今回は以下のアプリケーションを試してみることにしました。

Jaeger

www.jaegertracing.io

  • Uber Technologies が作っているやつ。
  • バックエンドのデータストアとして Cassandra, Elasticsearch が利用可能。
  • OpenTracing という規格に対応

Elastic APM

www.elastic.co

  • Elastic が作っているやつ
  • 当然バックエンドは Elasticsearch
  • OpenTracing という規格に対応

どのように処理を記録していくのか?

https://www.jaegertracing.io/docs/1.16/architecture/ から引用

f:id:mashijp:20191228163919p:plain

処理の単位を Span と呼び、 Span は親を持つことができます。 Span の塊を Trace と呼びます。

「分散」トレーシングにおいては別のマイクロサービスに対しコンテキストを渡す…などの概念がありますが、今回はモノリシックアプリケーション内でのトレーシングを目標としているので、割愛します。

また、使うミドルウェアによって多少言葉は異なりますが、大まかには同じです。

次回以降、実装例を紹介します。