Feedforce Developer Blog

フィードフォース開発者ブログ

Heroku Ruby Language Metrics のメトリクス収集の仕組みを調べた

こんにちは。id:masutaka26 です。

半年くらい前から Heroku の Ruby Language Metrics (Public Beta) を使い始めました。その時、どのようにメトリクスを収集しているか調べたので、この記事にまとめます。(なぜこのタイミング...)

有効にする方法は前述の公式ドキュメントをどうぞ。id:sho7650 の記事も併せて読むと分かりやすいと思います。

qiita.com

ところで、いつから Public Beta だったのですかね? GA はいつになるのかな...?

概要

今回は Rails 前提で説明します。このような仕組みでメトリクスの収集と送信が行われます。

  1. heroku/metrics buildpack により、Dyno 起動時に agentmon がインストールされ、常駐する
  2. Rails が起動すると、barnes gem がメトリクスを収集し始め、定期的に localhost の agentmon に送信する
  3. agentmon は https://app.metrics.heroku.com/<dyno id> にメトリクスを送信する
  4. エンジニアは Heroku Dashboard から Ruby のメトリクスを閲覧できる

agentmon のインストールと起動

heroku/metrics buildpack によって、agentmon というデーモンがインストールされます。

heroku/agentmon

agentmon は後述する barnes gem から受け取ったメトリクスを https://app.metrics.heroku.com/<dyno id> に送信します。

この URL は環境変数 HEROKU_METRICS_URL の値で、Heroku Dashboard から Enhanced Language Metrics を有効にすると、各 Dyno で定義されます。

面白いのは、Slug 生成時には /app/.profile.d/heroku-metrics-daemon.sh がインストールされるだけで、Dyno 起動時にこのスクリプトが実行され、agentmon のインストールと起動が行われることです。

Dyno では通常 Puma などのプロセスしか起動されませんが、このような方法を使えばデーモンも起動できることを初めて知りました。

ちなみに Dyno が起動する時 /etc/profile によって /app/.profile.d/*.sh がすべて実行されます

barnes gem によるメトリクス収集と送信

heroku/barnes

Rails が起動すると、Barnes.start から呼ばれる Barnes::Periodic.new で Ruby のスレッドが作られます。

Barnes.start はすぐに終了しますが、作られたスレッドは非同期で実行されます。無限ループのスレッドなので、Rails が起動している間、起動し続けます。

この無限ループでは 10 秒に 1 回、後述するメトリクスを収集し、localhost の agentmon に送信します。

送信するのはスレッド中のインスタンス変数 @reporter です。これは Barnes::Reporter のインスタンスで、statsd_client を介して agentmon に送信します。

statsd_clientBarnes::Reporter.new 時に渡されます。 https://github.com/heroku/barnes/blob/v0.0.8/lib/barnes.rb#L51

収集されるメトリクス

Barnes::ResourceUsage では収集されるメトリクスを一望できます。 https://github.com/heroku/barnes/blob/v0.0.8/lib/barnes/resource_usage.rb#L28-L63

収集されるメトリクスと、収集方法です。

まとめ

Heroku Ruby Language Metrics のメトリクス収集の仕組みを調べました。

ただ有効にするだけだと、他のエンジニアに説明することができなかったことが、今回調べた動機です。

今回に限りませんが、Heroku は完全なブラックボックスではなく、調べると実装が透けて見えるのがとても良いと思います。