Uber JVM Profiler は、CPU/メモリ/IO メトリクスなど、Hadoop/Spark JVM プロセスのさまざまなメトリクスとスタックトレースを分散方法で収集する Java エージェントを提供します。
Uber JVM Profiler は、ユーザー コードを変更することなく、ユーザー コード上の任意の Java メソッドと引数をトレースする高度なプロファイリング機能も提供します。この機能を使用すると、各 Spark アプリケーションの HDFS ネーム ノード呼び出しレイテンシーを追跡し、ネーム ノードのボトルネックを特定できます。また、各 Spark アプリケーションが読み取りまたは書き込みする HDFS ファイル パスを追跡し、ホット ファイルを特定してさらに最適化することもできます。
このプロファイラーは、通常、単一のアプリケーションに数十または数百のプロセス/マシンを含む Spark アプリケーションをプロファイリングするために最初に作成されたため、ユーザーはこれらの異なるプロセス/マシンのメトリクスを簡単に関連付けることができます。これは汎用 Java エージェントでもあり、あらゆる JVM プロセスにも同様に使用できます。
mvn clean package
このコマンドは、ConsoleOutputReporter、FileOutputReporter、KafkaOutputReporter などのデフォルト レポーターがバンドルされたjvm-profiler.jarファイルを作成します。 RedisOutputReporter や InfluxDBOutputReporter などのカスタム レポーターを jar ファイルにバンドルする場合は、ビルド コマンドでそのレポーターの Maven プロファイル ID を指定します。たとえば、RedisOutputReporter を使用して jar ファイルをビルドするには、 mvn -P redis clean package
コマンドを実行できます。利用可能なカスタム レポーターとそのプロファイル ID については、pom.xml ファイルを確認してください。
jvm-profiler jar ファイルを HDFS にアップロードすると、Spark アプリケーションの実行プログラムがそれにアクセスできるようになります。次に、Spark アプリケーションの起動時に次のような構成を追加します。
--conf spark.jars=hdfs://hdfs_url/lib/jvm-profiler-1.0.0.jar
--conf spark.executor.extraJavaOptions=-javaagent:jvm-profiler-1.0.0.jar
次のコマンドは、プロファイラー エージェントが接続されたサンプル アプリケーションを起動し、メトリクスをコンソール出力に報告します。
java -javaagent:target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,tag=mytag,metricInterval=5000,durationProfiling=com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod,argumentProfiling=com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1,sampleInterval=100 -cp target/jvm-profiler-1.0.0.jar com.uber.profiling.examples.HelloWorldApplication
次のコマンドを使用して、実行可能な jar アプリケーションで jvm プロファイラーを実行します。
java -javaagent:/opt/jvm-profiler/target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,metricInterval=5000,durationProfiling=foo.bar.FooAppication.barMethod,sampleInterval=5000 -jar foo-application.jar
Tomcat サーバーを起動する前に、CATALINA_OPTS で jvm プロファイラーを設定します。 logs/catalina.out ファイルでメトリクスを確認してください。
export CATALINA_OPTS="$CATALINA_OPTS -javaagent:/opt/jvm-profiler/target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,metricInterval=5000,durationProfiling=foo.bar.FooController.barMethod,sampleInterval=5000"
Spring Boot 2.x で jvm プロファイラーを使用するには、次のコマンドを使用します。 Spring Boot 1.x の場合は、次のコマンドで-Dspring-boot.run.jvmArguments
の代わりに-Drun.arguments
を使用します。
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-javaagent:/opt/jvm-profiler/target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.ConsoleOutputReporter,metricInterval=5000,durationProfiling=foo.bar.FooController.barMethod,sampleInterval=5000"
Uber JVM Profiler は、Kafka へのメトリクスの送信をサポートしています。例えば、
java -javaagent:target/jvm-profiler-1.0.0.jar=reporter=com.uber.profiling.reporters.KafkaOutputReporter,metricInterval=5000,brokerList=localhost:9092,topicPrefix=profiler_ -cp target/jvm-profiler-1.0.0.jar com.uber.profiling.examples.HelloWorldApplication
メトリクスを Kafka トピック profiler_CpuAndMemory に送信します。メトリクスの例については、このドキュメントの下部を参照してください。
JVM プロファイラーのブログ投稿を参照してください。
Uber JVM Profiler は次の機能をサポートしています。
Java ヒープ メモリ、非ヒープ メモリ、ネイティブ メモリ (VmRSS、VmHWM)、メモリ プール、バッファ プール (ダイレクト/マップ バッファ) を含む、すべての Spark アプリケーション エグゼキュータのメモリ使用量をデバッグします。
すべての Spark Executor の CPU 使用率とガベージ コレクション時間をデバッグします。
任意の Java クラス メソッドをデバッグします (実行回数、所要時間)。私たちはこれを期間プロファイリングと呼んでいます。
任意の Java クラス メソッド呼び出しをデバッグし、その引数の値をトレースします。これを引数プロファイリングと呼びます。
スタックトラック プロファイリングを実行し、フレームグラフを生成して、Spark アプリケーションに費やされた CPU 時間を視覚化します。
デバッグ IO メトリクス (アプリケーションのディスク読み取り/書き込みバイト、マシンの CPU iowait)。
合計スレッド数、ピークスレッド数、ライブ/アクティブスレッド数、新規スレッド数などのJVMスレッドメトリクスをデバッグします。
Java エージェントは次のパラメータをサポートしており、「-javaagent:agent_jar_file.jar=param1=value1,param2=value2」のように Java コマンド ラインで使用できます。
レポーター: レポーターのクラス名。例: com.uber.profiling.reporters.ConsoleOutputReporter または com.uber.profiling.reporters.KafkaOutputReporter。これらはコードにすでに実装されています。独自のレポーターを実装し、ここで名前を設定することもできます。
configProvider: 構成プロバイダーのクラス名 (例: com.uber.profiling.YamlConfigProvider)。これはコードにすでに実装されています。独自の構成プロバイダーを実装し、ここで名前を設定できます。
configFile: YamlConfigProvider によって使用される構成ファイルのパス (configProvider が com.uber.profiling.YamlConfigProvider に設定されている場合)。これは、ローカル ファイル パスまたは HTTP URL である可能性があります。
tag: メトリクスとともにレポートされるプレーン テキスト文字列。
metricInterval: メトリクスを収集して報告する頻度 (ミリ秒単位)。
durationProfiling: 特定のクラスとメソッドをプロファイルするように設定します (例: com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod)。また、メソッド名のワイルドカード (*) もサポートします (com.uber.profiling.examples.HelloWorldApplication.* など)。
argumentProfiling: 特定のメソッド引数をプロファイルするように設定します。例: com.uber.profiling.examples.HelloWorldApplication.publicSleepMethod.1 (「.1」は、最初の引数の値を取得してレポーターに送信することを意味します)。
sampleInterval: スタックトレース サンプリングを実行する頻度 (ミリ秒)。この値が設定されていないかゼロの場合、プロファイラーはスタックトレース サンプリングを実行しません。
ioProfiling: IO メトリクスをプロファイリングするかどうか。true または false になります。
BrokerList: com.uber.profiling.reporters.KafkaOutputReporter を使用する場合のブローカー リスト。
topicPrefix: com.uber.profiling.reporters.KafkaOutputReporter を使用する場合のトピックのプレフィックス。 KafkaOutputReporter は、この値をトピック名のプレフィックスとして使用して、メトリクスを複数のトピックに送信します。
OutputDir: com.uber.profiling.reporters.FileOutputReporter を使用する場合の出力ディレクトリ。 FileOutputReporter は、メトリックをこのディレクトリに書き込みます。
パラメーターは、Java コマンドの引数として指定することも、configProvider=com.uber.profiling.YamlConfigProvider を使用する場合は YAML 構成ファイルで指定することもできます。以下は YAML 構成ファイルの例です。
reporter: com.uber.profiling.reporters.ConsoleOutputReporter
metricInterval: 5000
以下は、ConsoleOutputReporter または KafkaOutputReporter を使用する場合の CPU とメモリのメトリクスの例です。
{
"nonHeapMemoryTotalUsed" : 11890584.0 ,
"bufferPools" : [
{
"totalCapacity" : 0 ,
"name" : " direct " ,
"count" : 0 ,
"memoryUsed" : 0
},
{
"totalCapacity" : 0 ,
"name" : " mapped " ,
"count" : 0 ,
"memoryUsed" : 0
}
],
"heapMemoryTotalUsed" : 24330736.0 ,
"epochMillis" : 1515627003374 ,
"nonHeapMemoryCommitted" : 13565952.0 ,
"heapMemoryCommitted" : 257425408.0 ,
"memoryPools" : [
{
"peakUsageMax" : 251658240 ,
"usageMax" : 251658240 ,
"peakUsageUsed" : 1194496 ,
"name" : " Code Cache " ,
"peakUsageCommitted" : 2555904 ,
"usageUsed" : 1173504 ,
"type" : " Non-heap memory " ,
"usageCommitted" : 2555904
},
{
"peakUsageMax" : -1 ,
"usageMax" : -1 ,
"peakUsageUsed" : 9622920 ,
"name" : " Metaspace " ,
"peakUsageCommitted" : 9830400 ,
"usageUsed" : 9622920 ,
"type" : " Non-heap memory " ,
"usageCommitted" : 9830400
},
{
"peakUsageMax" : 1073741824 ,
"usageMax" : 1073741824 ,
"peakUsageUsed" : 1094160 ,
"name" : " Compressed Class Space " ,
"peakUsageCommitted" : 1179648 ,
"usageUsed" : 1094160 ,
"type" : " Non-heap memory " ,
"usageCommitted" : 1179648
},
{
"peakUsageMax" : 1409286144 ,
"usageMax" : 1409286144 ,
"peakUsageUsed" : 24330736 ,
"name" : " PS Eden Space " ,
"peakUsageCommitted" : 67108864 ,
"usageUsed" : 24330736 ,
"type" : " Heap memory " ,
"usageCommitted" : 67108864
},
{
"peakUsageMax" : 11010048 ,
"usageMax" : 11010048 ,
"peakUsageUsed" : 0 ,
"name" : " PS Survivor Space " ,
"peakUsageCommitted" : 11010048 ,
"usageUsed" : 0 ,
"type" : " Heap memory " ,
"usageCommitted" : 11010048
},
{
"peakUsageMax" : 2863661056 ,
"usageMax" : 2863661056 ,
"peakUsageUsed" : 0 ,
"name" : " PS Old Gen " ,
"peakUsageCommitted" : 179306496 ,
"usageUsed" : 0 ,
"type" : " Heap memory " ,
"usageCommitted" : 179306496
}
],
"processCpuLoad" : 0.0008024004394748531 ,
"systemCpuLoad" : 0.23138430784607697 ,
"processCpuTime" : 496918000 ,
"appId" : null ,
"name" : " 24103@machine01 " ,
"host" : " machine01 " ,
"processUuid" : " 3c2ec835-749d-45ea-a7ec-e4b9fe17c23a " ,
"tag" : " mytag " ,
"gc" : [
{
"collectionTime" : 0 ,
"name" : " PS Scavenge " ,
"collectionCount" : 0
},
{
"collectionTime" : 0 ,
"name" : " PS MarkSweep " ,
"collectionCount" : 0
}
]
}
すべてのメトリクスとそれらに対応する情報のリストは、ここにあります。
Stacktrack Profiling の出力を取得してフレームグラフを生成し、CPU 時間を視覚化できます。 Python スクリプトstackcollapse.py
を使用して、次のコマンドを実行すると、Stacktrack Profiling json 出力ファイルがフレームグラフ生成用の入力ファイル形式に折りたたまれます。スクリプトflamegraph.pl
、FlameGraph にあります。
python stackcollapse.py -i Stacktrace.json > Stacktrace.folded
flamegraph.pl Stacktrace.folded > Stacktrace.svg
フレームグラフを生成するには、スタックトレース サンプリングを有効にする必要があることに注意してください。有効にするには、 sampleInterval
パラメータを設定してください。設定されていないかゼロの場合、プロファイラはスタックトレース サンプリングを実行しません。