Ruby VM の測定

Ruby 仮想マシンの挙動を理解することは、アプリケーション全体のパフォーマンスの理解とそれを向上させるのに役立ちます。New Relic は、Ruby VM が何をしているかについて、理解を助けるためのキーとなるメトリックを収集します。この情報は、アプリのパフォーマンスを向上させるために VM の構成を調整する際に、その影響を評価するのに役立ちます。

必須要件

Ruby VM メトリックの収集は、Ruby エージェントのバージョン 3.8.0 以上で使用できます。(ただし、以前のバージョンでもいくつかの基本的なガベージコレクションの測定値の収集をサポートしています)

また、この機能を使用するには、MRI(MatzのRubyのインタプリター、一般的に使用されているるRubyの実装)1.9.2 以上と互換性のあるRuby バージョンが必須となります。個々の測定について説明する以下のセクションで、Rubyのバージョンは、各測定の収集をサポートしています。

最後に、GC の実行タイミングを捕捉するには、アプリケーションにおいて GC::Profiler を有効にする必要があります。

Ruby VM データの表示

Ruby VM のパフォーマンスデータを表示するには、APM > (選択したアプリ) > Monitoring > Ruby VMsを選択します。このダッシュボードには、Ruby エージェントのバージョンが 3.8.0 以上を使っているアプリケーションのみが表示されます。

測定の詳細

以下のメトリクスの多くが Ruby のガベージコレクターの挙動を理解するのに役立ちます。

すべてのメトリクスが、すべてのRubyのバージョン間で収集できるわけではありません。MRIの最新バージョンを使っているのであれば、一般的に、ほぼ完全なデータを取得できます。以下のリストでは、何のメトリックがどこで取得できるかを示しています。

Object allocations [オブジェクトの割り当て]
利用可能: MRI 2.0+プロセスに割り当てられた Ruby のオブジェクトの数。リクエストごとに割り当てられるオブジェクトの数の直感的に理解できるように、UIではこの測定をリクエスト数によって正規化し、提示しています。

オブジェクト割り当ての頻度は、Ruby ガベージコレクターの実行頻度に関連する最たる理由のひとつです。よって、注意してみておく必要のある数字です。

MRI 上では、この値は、GC.stat[:total_allocated_object] から取得できます。

ガーベッジコレクションに掛かる時間
利用可能: MRI 1.9.2+, Rubinius 2.x ((JRuby のサポートについては、下記の注意をご覧ください)

Ruby プロセスにおけるガーベッジコレクション(マーク付と破棄の両フェーズ)にかかった時間の合計。

Ruby エージェントは、実際には異なる2つの方法でこの値を測定します。リクエスト処理の途中で発生したガベージコレクションの時間およびガベージコレクション合計時間。どういうこと?2つの方法じゃないの?
リクエスト処理の途中で発生したガベージコレクションの時間は、メインの Overview グラフ上にバンドとして表示します。そして、トランザクション別では、内訳表に表示されます。あってる?ウォールクロックタイムの割合として、合計 GC 時間が Ruby VM タブに表示されます。

この測定値は、GC::Profiler.total_time から取得できます。

: この測定値を取得するには GC::Profiler を有効にする必要があります。詳しくは、GC 計測をご覧ください。

JRuby メモ: JRuby や 特定のバージョンのJVMにおいて、バグと思われる要因のため、JRuby 上でGC のタイミングは、1000の要素でオフになることがあります。よって、現在、JRuby で GC::Profiler を有効にすることはお薦めしません。

ガーベッジコレクターの実行頻度
利用可能: MRI 1.9.2+、JRuby 1.7+、Rubinius 2.x

ガーベッジコレクターを実行するには、Rubyのプロセスを停止する必要がある頻度はどれくらいだろうか?MRI 2.1+ では、メジャーとマイナー GCの実行に分割されます。この数は、GCの実行ごとに処理要求の数としてUIで表示されます。

お使いの Ruby のバージョンに応じて、この値を、GC.count から、もしくは、GC.stat[:minor_gc_count]GC.stat[:major_gc_count] から抽出します。

Ruby のヒープサイズ
利用可能: MRI 1.9.2+

Ruby インタプリタは、heap上にオブジェクトを保存しています。各オブジェクトが単一のヒープスロットを占有します。ヒープ内のスロットがオブジェクトでいっぱいになると、ヒープは必要に応じてのRuby VMによって展開されます

Ruby エージェントは、ヒープ内の live オブジェクトの数、および定期的に占有されていないヒープスロットの数の両方を測定します。

一般的に言って、ヒープ上にオブジェクトがあればあるほど、(潜在的に、ヒープ上の全オブジェクトを検査しなければならないため)各GCの実行には時間がかかるようになります。また、ヒープ上あるオブジェクトの数と、アプリケーションのメモリ使用率には相関関係があります。

この値は、GC.stat[:heap_live_slot] または GC.stat[:heap_live_num]GC.stat[:heap_free_slot] または GC.stat[:heap_free_num] から取得できます。

メモリ使用量
利用可能: 全 Ruby バージョン

この測定は、Ruby プロセスのメモリ使用量(物理メモリの消費量)です。インスタンス(プロセス)あたりの平均サイズとして表しています。Ruby VM の設定を調整するとき、メモリ使用量を抑えることは重要な考慮事項です。大きくなりすぎた場合は、ホストマシンがディスクへのページングを開始ししたり、ソフトウェア強制メモリの制限との衝突などを引き起こす可能性があります。

Linux ホストでは、これは、/proc/PID/statusVmRSS フィールドから取得できます。

メソッドのキャッシュ無効化率
利用可能: MRI 2.1+

メソッドがオブジェクトから呼び出されるたびに、Ruby はオブジェクトの祖先チェーンを検索して、メソッドの実装を配置する必要があります。この検索はコストがかかるたため、Ruby の VM は、これらの検索の結果をキャッシュしています。

MRI の古いバージョン(2.0 より前)では、単一のグローバルメソッドキャッシュがありました。キャッシュ全体の無効化など、さまざまな操作
機能がありました。

MRI 2.1 以上では、1つのクラスにおけるキャッシュ無効化の変更が、関係ないクラスのキャッシュエントリを捨てないように、グローバルキャッシュは、より小さな、クラスごとのキャッシュのセットに分割されています。

しかし、すべてのメソッドのキャッシュを無効にするような操作が残っています。Ruby エージェントは、このような無効化の発生頻度を測定し、リクエスト数に対して正規化した測定値を報告します。これにより、リクエストごとのメソッドキャッシュが無効化された回数についての情報を得ることができます。

より詳しい情報は、Aman Gupta 氏のこのブログポストをご覧ください。.

この値は、RubyVM.stat[:global_method_state] から抽出できます。

Constant cache invalidation rate [定数のキャッシュ無効化率]
利用可能: MRI 2.1+

Ruby は、上記の述べたメソッドキャッシュと似た方法で定数の位置をキャッシュします。Ruby エージェントは、グローバル定数キャッシュが無効化された回数を測定し、リクエストごとの無効化の平均回数としてレポートします。

この値は、RubyVM.stat[:global_constant_state] から取得できます。

Thread count [スレッド数]

利用可能: MRI 1.9.2+, JRuby 1.7+, Rubinius 2.x

Ruby エージェントでは、Rubyプロセス内のスレッド数を追跡できます。マルチスレッドの Web サーバーを使用している場合、スレッドプールの実際のサイズを確認するのに使えます。(開放されないスレッドが生成されている状況)スレッドリークが発生している場合にも強調表示できます。

バックグラウンドプロセス

デフォルトでは、全プロセスのデータは、UI 上の Ruby VM のダッシュボードで指定されたアプリ名の下に統合されます。つまり、Web とバックグラウンドプロセス (Resque、Sidekiq、DelayedJob など)の両方が同じ New Relic のアプリケーションにレポートしていると、データはおかしくなる可能性があります。

この問題を回避する方法は2つあります。

  1. Webアプリとバックグラウンドプロセスを New Relic 内で別のアプリケーションとして認識されるように分ける。方法は、app_name 設定、または NEW_RELIC_APP_NAME 環境変数を設定する。
  2. バックグラウンドプロセスの Ruby VM メトリクスの収集を無効にする。設定ファイル内で、disable_vm_sampler: true を設定する。もしくは、環境変数に NEW_RELIC_DISABLE_VM_SAMPLER=1 を設定する。

さらに詳しい情報

追加のドキュメントリソースは次のとおりです。

  • “Eating the 1.9 elephant” ブログポスト (我々自身のサイトの調整にガベージコレクションを使ったときに、New Relic が発見したこと)
  • APM Overview (APM の Overview ページの機能と詳細へドリルダウンする方法)
  • Transactions ページ (Transactions ダッシュボードの機能と詳細へドリルダウンする方法)
  • Ruby エージェントの設定 (一般の設定、プロキシ、トランザクショントレース、エラーコレクターを含む構成ファイルの値と更新手順について)