Heroku Dynoのリソース使用率をNew Relicで観測し、予期せぬアプリケーションの停止を防ぐ

所要時間:約 8分

New Relicは、クラウド・オンプレ問わずデジタルサービスを観測可能ですが、PaaSであるHeroku上に構築されたアプリケーションももちろん対象とすることができます。

ところでHeroku Dynoのメモリ周りでトラブルシュートをされたことがある方は多いのではないでしょうか。具体的には、アプリケーションのメモリ使用量が割り当てメモリ量を超過してR14R15といったエラーに遭遇するというケースです。New Relic APMはアプリケーションが稼働するJVM等のメモリ使用量は取得可能ですし、OSレベルのリソース使用量もNew Relic Infrastructureで取得することができます。一方で、HerokuはPaaSですのでアプリケーション側からは手の届かないHerokuのDynoのレベルでのリソース利用量の情報を取得するには工夫が要ります。ここでは、Heroku Dynoがログに出力する実行時のメモリ使用量の情報をNew Relicに転送して監視する方法をご紹介します。

大まかな流れは以下画像の通りです。Heroku Dynoから標準出力に出力されるランタイムのログをsyslog drain経由でNew Relicに転送します。さらに、New Relicに転送されたログを構文解析して、メモリ使用量のデータとして取り込み、可視化やアラート定義をします。

 

設定手順は以下です。

  1. Heroku Dynoのlog-runtime-metrics機能を有効にして、実行時のメモリ使用量をログ出力する
  2. Heroku DynoのログをNew Relicに転送する設定をする
  3. New Relicに転送されたログの構文解析ルールを定義し、メモリ使用量をデータとして登録する
  4. メモリ使用量のデータを活用してDashboard / Alertを定義する

一つ一つ説明していきます。

 

1. Heroku Dynoのlog-runtime-metrics機能を有効にして、実行時のメモリ使用量をログ出力する

Herokuの実験的なサポート機能ですが、Dyno実行中のメモリ使用量をログ出力するための機能(log-runtime-metrics)が利用可能なので、以下のコマンドで有効にします。

heroku labs:enable log-runtime-metrics -a <Dynoアプリケーション名>

これでDynoのログにメモリ使用量の情報が出力されるようになります。

2. Heroku DynoのログをNew Relicに転送する設定をする

Heroku Dynoが出力するログをNew Relicに転送します。設定方法については別のブログ記事(Heroku上のログを直接統合できるようになりました)をご参照ください。設定が完了すると、New Relic Logs UIにてメモリ使用量に関するログが出力されていることが確認できます。

3. New Relicに転送されたログの構文解析ルールを定義し、メモリ使用量をデータとして登録する

前のステップでNew Relicにログが登録されていることを確認できました。ただし、このままではログが平文で登録されているのでログに含まれるいくつかのメトリクスを解析したり、アラート通知するのが困難です。New Relicでは、ログのメッセージをデータ登録する際に構文解析ルールを適用して自動的に属性に展開して保存することが可能です。これによりデータ登録後に可視化したり、アラート設定するのが非常に楽になります。

ログの構文解析ルールは、New Relic LogsのUIから設定可能です。解析ルールの設定方法の詳細は、オンラインドキュメントを参照してください。

UI上右の「・・・」メニューより「Manage parsing」を選択し、解析ルールを定義します。

Heroku Dynoのログは以下の形式で出力されますので、この形式に対応したカスタムの構文解析ルールを定義します。

source=scheduler.6924 dyno=xxxxx sample#memory_total=193.72MB sample#memory_rss=193.47MB sample#memory_cache=0.25MB sample#memory_swap=0.00MB sample#memory_pgpgin=51918pages sample#memory_pgpgout=2325pages sample#memory_quota=512.00MB

 

以下は、カスタムの構文解析ルールの一例です。ルールはGrokパターンで指定します。memory_totalの値はmemory_totalという属性として、memory_rssの値はmemory_rssとして登録されます。

source=%{USERNAME:source_name} dyno=%{USERNAME:dyno} sample#memory_total=%{NUMBER:memory_total}MB sample#memory_rss=%{NUMBER:memory_rss}MB sample#memory_cache=%{NUMBER:memory_cache}MB sample#memory_swap=%{NUMBER:memory_swap}MB sample#memory_pgpgin=%{INT:memory_pgpgin}pages sample#memory_pgpgout=%{INT:memory_pgpgout}pages sample#memory_quota=%{NUMBER:memory_quota}MB

 

Dynoのランタイムログだけにこのルールを適用するために適用の条件を指定します。今回の場合は、ソースがHerokuであること、ログテキストにmemory_totalなどが含まれるといった条件が適しています。

New RelicのQuery Builderでログを検索してみます。下記画像の通り、ログメッセージに含まれていた各種リソースの情報が、構文解析ルールに基づいて属性に展開されていることがわかります。

 

4. メモリ使用量のデータを活用してDashboard / Alertを定義する

データが登録されていることが確認できましたので、実際にDaashboardやAlertを定義してDynoのメモリ不足や予期せぬ停止に備えます。

Alert定義

Logイベントの属性値としてmemory_totalやmemory_rssが格納されているので、この値に対するアラートを設定します。以下のようにNRQLによる検索結果に対するアラートとして定義します。注意点としては、属性値は文字列として格納されているため、numeric関数を使って数値に変換しておくことです。

FROM Log SELECT average(numemric(memory_total)) where memory_total is not null facet source_name

Dashboard定義

同様に、Logイベントの属性値として格納されているmemory_totalやmemory_rssの最新値や推移をダッシュボードに可視化することで、リアルタイムに現状把握が行えるようになります。例えば、以下のクエリはmemory_totalの平均値をLine Chartで表示します。今回はmemory_totalを例としていますが、データとして取得している他のメトリクス (memory_rss)なども同様にチャートにすることは可能です。

FROM Log SELECT average(numeric(memory_total)) where memor_total is not null timeseries

以上が、Dynoの実行時のリソース使用量をログ出力してNew Relicに取り込むことによって、PaaSであるHeroku自身のリソース使用量も監視するための方法です。これにより予期せずアプリケーションが停止するということが避けられるようになること、New Relicが収集するその他のテレメトリーデータ(アプリケーションやリアルユーザ)も含めてシステム全体の観測性を高めることが可能になります。今回はHerokuを題材にしましたが、例えばAWSのサービスのログなども同様です。そちらに関しては別の投稿(Amazon S3に保存したログをNew Relicに取り込む)をご参考にしてください。

 

New Relicを試してみたい方はこちらへ。

無料トライアル