Goの無料Continuous Profilingを試みる

Continuous Profilingとは…!

本番環境で継続的にプロファイリングをすること。
本番環境で稼働するアプリケーションには大体DatadogやらGCPならCloud Profilerなど何かしらサービスを導入することで可能にするだろう。

自分的には本番じゃなくてもContinuous Profilingをしたいときはあって、負荷試験中がそのときなのだ。
負荷試験中でもDatadogなりつかってしまえばいいのだが、まあ色々な理由で使えない時もある。

負荷試験中のContinuous Profiling

負荷試験が10分そこらで終わるケースなら、単にnet/http/pprofを利用してpprof参照用のAPIを公開しておいて負荷試験が終わったタイミングでアクセスすればOK!となるだろう。

しかし、自分が負荷試験をやるような場合はだいたい10分そこらで終わらないし、1ケースが10分そこらでも1ケース終わるごとに結果を参照するなんて面倒なことはしない。
数時間放っておいて終わった頃合いですべての結果をざっと見たいのだ。

また、負荷をかけられているアプリケーションがpprof参照用のAPIを公開しているようなケースだとノックアウトされたときにアプリケーションをホストするコンテナが停止、削除されたときに ナニモワカラン になる。

GoでもDatadogのProfilerはリアルタイムにメトリクスをpprofパッケージを利用し取得してDatadogへ送りつけている。

要はDatadoの代わりになりそうなOSSのツールを探すぞ。ということだ。
OSSのツールなら無料で動くはず!

探してみた

なんとなく良さげなもの二つ見つけた。
profefeは最近はコミットがないようだが、2020年末時点ではMirrativeが本番で利用している情報をキャッチした。

pyroscope動かしてみた

https://pyroscope.io/docs/golang/#profiling-go-application
を参考にする。
pyroscope.Configで設定する
ServerAddress: "http://pyroscope-server:4040"
というのがミソでメトリクスを送りつける先を指定する。
送りつけられる側は
https://pyroscope.io/docs/docker-guide/
を参考に起動する。

Goのpyroscope clientの設定では例にServerAddressに "http://pyroscope-server:4040"を指定させているがDocker Composeの例でサービス名がpyroscopeになっているので注意。

なんら難しいことはなくサクッと動かせる。

Pullモード

Profiling対象のアプリケーションがGoの場合のみのようだがPullモードなるものがある。
なの通り、pyroscopeのサーバがアプリケーションサーバへPullしてくれる。
net/http/pprofを利用してpprofを公開してpyroscopeの設定に取得先を記述するだけで動く便利な代物だ。

https://pyroscope.io/docs/golang/#pull-mode
https://pyroscope.io/docs/golang-pull-mode/

profefe動かしてみた

こちらも単に動かすのは楽勝だ。
↓を参考に、アプリケーションにメトリクス取得のためのプロセスを組み込む。
https://github.com/profefe/profefe/blob/master/examples/server/main.go

次にメトリクスを集めるプロセスを起動する。
↓をみるとdocker-compose上での使い方がわかるので参考になるはずだ。
https://github.com/profefe/profefe/blob/master/docker-compose.yml
ちなみに、メトリクスを集めるプロセスを起動するコマンドのオプションにドキュメントがない。

Run ./BUILD/profefe -help to show the list of all available options.

とREADMEにある。brewやaptで落とせるツールならサッと確認できるがそうでもないのでオプションを確認するのに工夫がいる。

↓にあるようにdocker経由コマンドをサクッと実行できるので、ここからhelpを実行するとイイ。
https://github.com/profefe/profefe/tree/master/contrib/docker

S3をバックエンドに使う

デフォルトでprofefeはバックエンドにbadgerを利用する。
ちなみにpyroscopeもbadgerを利用する。pyroscopeにはバックエンドを変更するオプションはないようだが。

このバックエンドをS3にすることができる。
どうすればいいか。っていうのはドキュメントにとくにないので雰囲気と勘でやるっきゃない。
helpコマンドを実行するとどうやらS3を使うにはオプションを埋めていく必要があるのがわかる。

❯ docker run -it profefe/profefe:latest -help
Usage of /profefe:
  -addr string
    	address to listen (default ":10100")
  ~~~ 略 ~~~
  -s3.bucket string
    	s3 bucket profile destination
  -s3.disable-ssl
    	disable SSL verification
  -s3.endpoint-url string
    	override default URL to s3 service
  -s3.max-retries int
    	s3 request maximum number of retries (default 3)
  -s3.region string
    	object storage region (default "us-east-1")
  -storage-type string
    	storage type: badger, clickhouse, s3, gcs (default "auto")
  -version
    	print version and exit

想像できるのはprofefeはS3のPutObjectなんかをSDKから呼び出すのだろうと….
するとここから他にやることはないか?と考えてみるとAWSのクレデンシャルが環境変数なり何処かへあるべきじゃないかと。
で、最終的にはdocker-compose.yml内では以下のように宣言した。
S3の代わりにはminioを使っている。

version: '3'

services:
  // 略
  profefe-collector:
    image: profefe/profefe:latest
    environment:
      - AWS_ACCESS_KEY_ID=minio
      - AWS_SECRET_ACCESS_KEY=minioadmin123
      - AWS_DEFAULT_REGION=us-east-1
    command:
      - -addr=:10100
      - -s3.endpoint-url=http://minio:9000
      - -s3.disable-ssl=true
      - -storage-type=s3
      - -s3.bucket=profefe
    ports:
      - 10100:10100
  minio:
    image: minio/minio:latest
    command: server /data --console-address 0.0.0.0:34501
    volumes:
      // NOTE: 予めホストマシンの ./minio/data/profefeのディレクトリを作成しておき、minio上でのbucketは存在している状態を作る。
      - ./minio/data:/data    
    ports:
      - 19000:9000
      - 34501:34501
    environment:
      MINIO_ROOT_USER: minio
      MINIO_ROOT_PASSWORD: minioadmin123

これで起動するとS3のBucket(minio)にファイルが溜まっていく。

このファイル1つ1つはpprofファイルなのでダウンロードしてツールに取り込むと普通に使える。

go tool pprof ~/Downloads/cav8j43rardc73fv3v0g,host=localhost
File: main
Type: inuse_space
Time: Jul 1, 2022 at 2:43pm (JST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) web

直接ダウンロードしてみるケースが果たしてあるかはまた別問題であるが…

使い様を想像してみる

pyroscopeのほうが組み込みのUIがリッチでイケている感じが出る。また、PullモードはGoのコード変更が最も少なく済む。
また、メトリクスのクエリができたり分析が容易かもしれない。
バックエンドがbadger固定だが、pyroscopeのサーバインスタンスが落ちてもデータロストしないようにprometheusと連携させたりする面倒さはあるかも。

profefeはシンプルでバックエンドがS3やGCSに変更できてprofefeをメトリクスのコレクターとしてサーブしているコンテナを落としても、別のプロセスでprofefeを起動すればメトリクスを参照できる。
シンプルゆえにメトリクスを参照するにはpprofを取り込める別のツールが必要になる。逆にpprofを取り込めるツールを活用できる。
Goを利用している場合、go tool pprofをシュッと使えるのであまり困らないかもしれない。

負荷試験なんかで使いたいなーってケースに立ち返ってみると、profefe寄りかもしれない。
prometheusを入れて、じゃあ次はGrafana入れたり…とかやり出したらキリなくなりそうだ。

負荷試験中ではS3と連携させたprofefeを稼働させておいて、終わったらgo tool pprofがシンプルではなかろうか。
負荷試験で使用したアプリケーションと共にprofefeも落としてしまってもS3にデータは残るので後から見返すのも容易だし。

まあ負荷試験中でもDatadog使えるのが一番楽だよね!

最後に

JMC慣れしているのでどのツール使ってもGUIに満足できない体になっている。

この記事が気に入ったらサポートをしてみませんか?