※本記事は、“Instrumenting applications with Java Flight Recorder” の翻訳記事です。

2022年3月22日 | 6分読む

Justine Kavanaugh-Brown


オーバーヘッドが低く、本番環境でも長時間にわたってプロファイリングを実行できるJava Flight Recorder

 

Java Flight Recorder(JFR)は、民間旅客機に搭載されるブラックボックスのように、実行中のJavaアプリケーションとJVMについての情報を継続的に記録します。JFRはオーバーヘッドが低いため、本番環境でも長時間にわたってプロファイリングを実行することができます。

先日行われた、オラクルのVice President of Java Developer RelationsであるChad ArimuraとオラクルでConsulting Member of Technical Staff を務めるMarkus Grönlundとの対談では、JFRとそれによって生まれるチャンス、JFRの始め方やストリームに関する新機能などが語られました。ここでは、その一部を紹介します。

Arimura: JFRと、それが解決する問題について簡単に説明してください。

Grönlund: 航空機内部のフライト・レコーダーが航空機に関する情報を記録し続けるように、JFRもJavaプログラムとその処理環境についての情報を記録します。その目的は、航空機のフライト・レコーダーによって、何が重大事故につながったのかを理解できるのとちょうど同じように、開発者やテスター、システム管理者が時間をさかのぼってアプリケーションのパフォーマンスについて理解できるようにすることです。

Arimura: JFRは、2018年にオープンソース・ソフトウェアとしてリリースされました。この点についてはいかがでしょうか。

Grönlund: JFRは長年にわたって商用製品でした。そのため、JFRを使って、本番環境で動作しているプログラムのトラブルシューティングを行うには、ライセンスが必要でした。ただし、開発者がコードを理解して改善するという開発目的であれば、このテクノロジーはもともと無償で利用できました。

2018年に、オラクルはJFRテクノロジーとそれに関連するツール・スイートであるJDK Mission Control(JMC)をOpenJDKコミュニティに寄贈しました。これにより、今は本番環境でも無償で利用できるようになっています。

JFRが新しく採用されたり、新しいユースケースが登場したりするのを見るのはうれしいことです。たとえば現在、JFRから提供される情報をクラウドへのデプロイなど、大規模なデプロイに活用する方法をいくつかのベンダーが検討しています。

Javaプラットフォームには、その中核に強力なサービス機能が組み込まれているという確かな伝統があります。JFRによって、本番環境で長時間にわたってプロファイリングを行うこともできるようになったので、開発者やユーザーはコードで何が起きているのかを理解する方法が増えることになります。

Arimura: 一般的な開発者がJFRを使う場合、どのように始めるのがよいでしょうか。

Grönlund: JDK 11以降など、比較的新しいJDKであれば、容易に使い始めることができます。このテクノロジーをJavaプラットフォームに組み込むことのメリットは、コマンドラインに1つのフラグを追加するだけでよくなることです。

-XX:StartFlightRecording

このコマンドで、バックグラウンドでの継続的な記録が開始されます。すると、問題が発生したときや、コードを実行して何が起きているかを知りたいときに、開発者やテスターが履歴を確認できるようになります。
記録した情報にアクセスするには、ファイルにダンプする必要があります。JFRの記録ファイルは情報が密に詰まったバイナリ・ファイルで、拡張子は.jfr です。情報をダンプする方法の1つは、次のようにして bin/jcmd ツールを使うというものです。

bin/jcmd <pid> JFR.dump filename=myrecording.jfr

ファイルが生成されたら、そのファイルをJMCで開いたり、bin/jfr ツールで分析したりすることができます。JDK Mission ControlのGUIから直接JFRを起動したり、ダンプを取得したりすることもできます。

Arimura: 現在、JFRからどのくらいの数のデータ・ポイントが出力されますか。特に重要なものやよく使われるものは何でしょうか。

Grönlund: 現在オラクルが公開しているJVMとJDKには、150種類のイベントが存在します。さらに、ほぼ常にいくつかのイベントが検討中や評価中の状態になっています。デフォルトのイベント・セットが設定されているので、詳しい知識がなくても使い始めてみることができます。よく使われているのは、次のようなものです。

  • GarbageCollection および GCPhasePause イベント・タイプは、高水準のガベージ・コレクション情報を提供します。これはアプリケーション開発者向きで、ガベージ・コレクションによる停止についての詳細情報などが含まれます。
  • ObjectAllocationSample イベントは、システムでのメモリ割当てに関する情報を提供します。オブジェクトの種類や割当ての場所といった情報がスタック・トレースで表現されます。このイベントはJDK 16で追加されました。これは、メモリ割当てに関する、以前のイベントを改善したもので、新しいスロットリング技術によって制限を行い、情報量を少なくしています。
  • JFRには、オブジェクトの割当てをサンプリングし、その生存時間を追跡して、メモリ・リークをピンポイントで発見する常時実行メモリ・リーク・プロファイラが搭載されています。メモリ・リークしているかもしれないとして、調査対象候補となる可能性があるオブジェクトを示すために、OldObjectSample イベントが発行されます。
  • JavaMonitorEnter イベントおよび JavaMonitorWait イベントは、ロックとモニターに関する情報を報告します。ここから、アプリケーションの動作が進まない理由を分析することができます。
  • Socket and File IO イベントから、入出力操作の詳細がわかります。データベースやネットワークの呼出しなど、コードが外部と通信する場合のレイテンシを把握するうえで役立ちます。

Arimura: 開発者がアプリケーション固有のJFRイベントを作ることもできますか。

Grönlund: もちろんです。 jdk.jfr module のAPIを使うと、開発者のアプリケーションや業務領域に適したイベントの設計が容易になります。

JFRのイベント・モデルは統一されているため、アプリケーションのコード、サードパーティ製ライブラリ、JDK、JVMのすべてを含むスタック全体の依存性や関連性を発見することができます。

Arimura: JDK 14で、JFR Event Streamingがリリースされました。その背景にある動機について教えてください。

Grönlund: JFRのもともとの設計は、主に本番環境のアプリケーションやシステムのプロファイリングやトラブルシューティングを目的としたものでした。しかし、監視や遠隔測定のソリューションにおいてJFRをデータソースとして使いたいというニーズは常にあり、増加も続けています。

JFR Event Streamingでは、記録したデータに継続的にアクセスすることができます。新しいJFR Event Streaming APIを使うと、選択した種類のイベントがイベント・ストリームに現れたときのコールバックを登録して実行したり、記録した情報に迅速に、つまりライブでアクセスしたりすることができます。

従来の監視や遠隔測定のソリューションの多くは、フラットなデータ・モデルを使ってカウンタや集計のようなスカラー値を報告しています。これは問題の検出には役立ちますが、何が問題を起こしている可能性があるのかを詳しく把握することは難しいかもしれません。

対照的に、JFR Event Streamingは問題解決にとても重要になる構造を保持しており、監視のユースケースでも問題解決を行います。たとえば、JFRからストリームされるデータ・ポイントでは、関連するスタック・トレースなどのコンテキスト情報との関係が維持されています。

Arimura: JDK 16では、JFR Remote Event Streamingという機能も追加されましたね。

Grönlund: はい。チームはJFR Event Streaming APIを拡張して、リモート・ホストのプロセスからのイベント・ストリーミングも可能にしました。内部的には、サーバーで起きていることを単純にリスニングするだけでなく、オリジナルのイベント・データのバイナリを転送し、クライアント側のディスクに継続的に書き込んでいます。これにより、監視を専用のホストにオフロードし、監視対象のシステムへの影響を最低限にとどめることができるので、大規模な監視ソリューションの設計や構成に役立ちます。

Arimura: 一般的なユーザーはイベントをフィルタリングすべきでしょうか。それとも、すべて許可するべきでしょうか。

Grönlund: JFR全般に言えることですが、JFR Event Streamingで推奨されるのは、できる限りデフォルトの状態で使うことです。デフォルトでは、記録プロセスのオーバーヘッドや生成されるデータ量など、さまざまな側面にわたってバランスがとれているからです。

JFR Event Streaming APIを使うと、イベントの種類ごとにハンドラやコールバックを設定することができますが、これが一種のフィルタリングになります。アップストリームのレイテンシ要件によっては、バックホールへの送信前にローカルでデータを集計し、情報を要約した方がよいかもしれません。

このストリーミング・プロセスで重要なのは、情報が失われないことです。これが可能なのは、履歴が継続的にディスクに記録されるからです。この履歴のおかげで、ユーザーは好きなときにデータを使うことができます。そのため、以前のパスで把握した情報を考慮しつつ、適切な時間にストリームを再開することができます。

Arimura: Java Flight Recorderは今後どのように進化するのでしょうか。

Grönlund: 私のチームは、Project Loomを担当するチームと密接に連携しています。非同期コードを正しく動作させるうえで特に問題になることの1つは、監視やプロファイリングの困難さです。分散タスクをトラッキングすることは難しく、わかりやすい形でデータを提供するのはいっそう困難です。

Project Loomは、プログラマーから見た作業から非同期タスクを取り除くことを目指しています。JFRとLoomを組み合わせることで、監視やプロファイリングに関連する非同期タスクも取り除けるようになるでしょう。

たとえば、Socket I/O呼出しなどの非同期操作を行う仮想スレッドも、JFRでは通常の同期操作と同じように見えるようになるでしょう。

JFRでProject Loomをサポートする作業はしばらく前に始まっており、現在、早期アクセス・ビルドで試すことができます。

[ 編集注:本記事は、Inside Javaポッドキャストのエピソード13:JDK Flight Recorderを抜粋要約したものです。]

 

さらに詳しく