serviceability toolsの裏側

56
Serviceability Tools ののの どどどどどどどどどどどどどど ど ~?~ 2013/05/11 どど どど @YaSuenag #ccc_r54

Upload: yasumasa-suenaga

Post on 25-May-2015

1.966 views

Category:

Technology


5 download

TRANSCRIPT

Page 1: Serviceability Toolsの裏側

Serviceability Toolsの裏側~どうやって情報をとってるの?~

2013/05/11末永 恭正  @YaSuenag #ccc_r54

Page 2: Serviceability Toolsの裏側

自己紹介 末永 恭正  @YaSuenag

某通信キャリアで Java の障害解析してますしたhs_error ログやコアの解析 などなど

ネイティブ寄りな Java プログラマ 基本サンデープログラマー

Pascal とか C とか Java とか…

すえなが やすまさ

Page 3: Serviceability Toolsの裏側

Serviceability Tools ?

Serviceability in the J2SE Repository http://openjdk.java.net/groups/serviceability/svcjdk.html

jconsole

jdbjhat

jinfo

jmap

jpsjcontrol

jsadebugd

jstack

jstat

jstatd

Page 4: Serviceability Toolsの裏側

Serviceability Technologies

http://openjdk.java.net/groups/serviceability/

Page 5: Serviceability Toolsの裏側

Dynamic Attachツールと JVM がカンタンに連携

Page 6: Serviceability Toolsの裏側

Dynamic Attach

ツールからの要求に応じて HotSpot が情報収集 各ツールと HotSpot の連係プレー

ツール側○ sun.tools.attach.HotSpotVirtualMachine の

提供するメソッドを実行○ 専用のコマンドと引数をターゲット VM へ送信

HotSpot 側○ Attach Listener が指定された処理を実行し、結果を

ツールへ返却"Attach Listener" daemon prio=10 tid=0x00007f92dc001000 nid=0x261e runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE

Page 7: Serviceability Toolsの裏側

各ツールと HotSpot の連携

Java プロセス( HotSpot VM )

各種ツール

①SIGQUIT 送信

※Linux の場合

②AttachListener起動

③ コマンド送信

④ 処理実行

④´ 処理結果

Unix ドメインソケット

Page 8: Serviceability Toolsの裏側

AttachListener のコマンド フォーマット

<ver>\0<cmd>\0<arg>\0<arg>\0<arg>\0AttachListener に与える命令ヌル文字( \0 )がデリミタ

項目ver

○ プロトコルバージョン(’ 1’ 固定)cmd

○ コマンドarg

○ コマンド引数(最大 3 つまで)

Page 9: Serviceability Toolsの裏側

AttachListener のコマンドコマンド 機能 利用ツールagentProperties エージェント用システムプロパ

ティの取得• jdb• jconsole• JMX エージェント

datadump SIGQUIT 送出(と等価) なしdumpheap ヒープダンプ生成 jmap

load JVMTI エージェントのロード jconsole

properties システムプロパティの取得 • jconsole• jinfo

threaddump スレッドダンプの取得 jstack

inspectheap クラスヒストグラムの取得 jmap

setflag 非推奨オプション (-XX) の設定 jinfo

printflag 非推奨オプション (-XX) の取得 jinfo

jcmd jcmd の実行 jcmd

enabledprobes DTrace プローブを有効にする※Solaris のみ

なし

Page 10: Serviceability Toolsの裏側

超簡単! AttachListener 利用 Java プログラム中の特定のポイント通過時の

クラスヒストグラムを取ってみるJava プログラムから、自分自身の VM にアタッチHotSpotVirtualMachine#heapHisto() を呼

び出す○ AttachListener 的には inspectheap コマンドを実

行するLinux の Java7 以降で動くものを作ります

Page 11: Serviceability Toolsの裏側

Java プログラム ※抜粋import java.io.*;import java.nio.file.*;import com.sun.tools.attach.*;import sun.tools.attach.*;

: Path selfProc = FileSystems.getDefault().getPath("/proc/self"); String pidString = Files.readSymbolicLink(selfProc).toString();

HotSpotVirtualMachine selfVM = HotSpotVirtualMachine)VirtualMachine.attach(pidString);

try(InputStream in = selfVM.heapHisto("-all")){ byte[] buf = new byte[1024]; int n;

while((n = in.read(buf)) > 0){ System.out.print(new String(buf, 0, n, "UTF-8")); }

} finally{ selfVM.detach(); }

PID 取得

アタッチ

AttachListener へコマンド送信

結果読み込み&

出力デタッチ

Page 12: Serviceability Toolsの裏側

ビルド&実行$ javac -cp $JAVA_HOME/lib/tools.jar AttachListenerTest.java$ java -cp $JAVA_HOME/lib/tools.jar:. AttachListenerTest

num #instances #bytes class name---------------------------------------------- 1: 13228 1462888 [C 2: 7477 1136592 <constMethodKlass> 3: 7477 1022984 <methodKlass> 4: 562 701568 <constantPoolKlass> 5: 2093 536728 [B 6: 562 396376 <instanceKlassKlass> 7: 502 395520 <constantPoolCacheKlass> 8: 579 265768 [I 9: 6120 146880 java.lang.String 10: 631 76696 java.lang.Class 11: 1003 65664 [S 12: 882 55808 [Ljava.lang.Object; 13: 2278 54672 java.lang.StringBuilder 14: 900 52952 [[I 15: 52 29536 <objArrayKlassKlass>

ソケットバッファ溢れに注意!

Page 13: Serviceability Toolsの裏側

jvmstat Performance Counters

JVM にインパクトを与えずにディープな情報を取得!

Page 14: Serviceability Toolsの裏側

jvmstat Performance Counters

通称” PerfCounter” HotSpot の統計情報を集めたファイル

/tmp/hsperfdata_< ユーザー名 >/<PID> 各種データは、このファイルにマップされた

仮想メモリ空間に直接保存GC 回数/時間ライブスレッド数etc…

各種ツールはこのファイルを直接参照してJVM の動作状況を収集する

Page 15: Serviceability Toolsの裏側

具体的に見てみる jcmd の PerfCounter.print

$ jcmd 2065 PerfCounter.print2065:java.ci.totalTime=0java.cls.loadedClasses=379java.cls.sharedLoadedClasses=0java.cls.sharedUnloadedClasses=0java.cls.unloadedClasses=0

:sun.rt.safepointSyncTime=22sun.rt.safepointTime=80sun.rt.safepoints=1sun.rt.threadInterruptSignaled=0sun.rt.vmInitDoneTime=1365171171705sun.threads.vmOperationTime=29sun.urlClassLoader.readClassBytesTime=165372sun.zip.zipFile.openTime=1010449sun.zip.zipFiles=2

Java レイヤから出してるPerfCounter

6878481: Add performance counters in the JDK

Page 16: Serviceability Toolsの裏側

トラップ!その1 tmpwatch

/tmp や /var/tmp を定期的にお掃除するツール○ Red Hat 系ディストロではおなじみ

/tmp/hsperfdata_< ユーザー名 > も消しやがる!○ ps ではプロセスが見えるのに JDK 付属ツールでア

タッチできない場合に疑うべきポイント○ RHBZ#527425 - /tmp/hsperfdata_${user}/${PID} is

deleted by tmpwatchやっぱり同じことで困ってる人がいましたFedora なら tmpwatch-2.9.16-1.fc13 から OK だそうです

Page 17: Serviceability Toolsの裏側

トラップ!その2 java.io.tmpdir

6u23 、 6u24 のみ該当○ 6938627: Make temporary directory use property

java.io.tmpdir when specified○ 7009828: Fix for 6938627 breaks visualvm

monitoring when -Djava.io.tmpdir is defined6938627 が入ったことで、各種ツールが動かな

くなってしまう人が続出○ 実は Dynamic Attach も影響を受けます

HotSpot混迷の時代

Page 18: Serviceability Toolsの裏側

超簡単!カスタム情報収集ツール PerfCounter から自分が欲しい情報を好きなフォーマットで出力します

出力する情報ライブスレッド数モニタ競合回数VM 総停止時間アプリケーション固有の統計情報

○ プログラムから PerfCounter にエントリを作ります

Page 19: Serviceability Toolsの裏側

Java プログラム ※抜粋

PerfCounter 生成メソッドsun.misc.PerfCounter#newPerfCounter を

呼び出すPackage private なのでリフレクションで呼び出

しprivate PerfCounter newPerfCounter(String name) throws Exception{ Method method = PerfCounter.class.getDeclaredMethod( "newPerfCounter", String.class); method.setAccessible(true); PerfCounter result = (PerfCounter)method.invoke(null, name); return result;}

Page 20: Serviceability Toolsの裏側

Java プログラム ※抜粋

呼び出しエントリ名はとりあえず以下のようにしてみる

○ perfCounter.test.< スレッド名>.invocations

String entryName = “perfCounter.test.” +          Thread.currentThread().getName() + ".invocations";

try{ this.perfCounter = this.newPerfCounter(entryName);

Page 21: Serviceability Toolsの裏側

jstat_options

jstat が使用する定義ファイル PerfCounter から収集する項目と出力方法を

定義したもの割合みたいな単純計算まで定義できます

$JAVA_HOME/lib/tools.jar に含まれてます$HOME/.jvmstat/jstat_options でオーバー

ライド可能

Page 22: Serviceability Toolsの裏側

カスタム版 jstat_optionsoption custom{ column { header "^Threads^" data java.threads.live scale raw align right width 4 format "0" } column { header "^MonitorContention^" data sun.rt._sync_Parks scale raw align right width 4 format "0" } column { header "^STW^" data (sun.rt.safepointTime/sun.os.hrt.frequency) scale raw align right width 6 format "0.000" }

column { header "^ThreadA^" data perfCounter.test.ThreadA.invocations scale raw align right width 3 format "0" } column { header "^ThreadB^" data perfCounter.test.ThreadB.invocations scale raw align right width 3 format "0" } column { header "^ThreadC^" data perfCounter.test.ThreadC.invocations scale raw align right width 3 format "0" }}

Page 23: Serviceability Toolsの裏側

実行結果$ jstat -custom 1806Threads MonitorContention STW ThreadA ThreadB ThreadC 7 21 0.117 7 6 5

インターバル設定しても変化がみられません

8011934 : sun.misc.PerfCounter calls Perf.createLong with incorrect parameters

Page 24: Serviceability Toolsの裏側

Serviceability Agentネイティブレイヤから直接情報を引っこ抜く最強ツール!

Page 25: Serviceability Toolsの裏側

Serviceability Agent

通称” SA” 機能

強制的なプロセスアタッチ○ Linux では ptrace(2) を使用○ jinfo や jmap 等の” -F” オプションで発動○ jstack では” -m” オプションでも発動

コア解析○ Linux ではコアイメージから Java レイヤの情報

(スレッドダンプやヒープダンプ)などを取得可能

○ ELF バイナリを debuginfo まで含め、自力でパースしてしまう!

Page 26: Serviceability Toolsの裏側

SA の情報ソース① シンボルテーブル

各バイナリを解析して、仮想メモリ空間のどこに、何が入っているのかを特定

② VMStructs JVM 中で使用する情報を保持する仮想メモリア

ドレスや各種オフセット位置をまとめた構造体配列

Java オブジェクトの C++表現( oop )のパースなど、様々な用途で使用

Page 27: Serviceability Toolsの裏側

VMStructs の中身 マクロで定義されてます

hotspot/src/share/vm/runtime/vmStructs.cpp

:nonstatic_field(CollectedHeap, _reserved, MemRegion) \nonstatic_field(SharedHeap, _perm_gen, PermGen*) \nonstatic_field(CollectedHeap, _barrier_set, BarrierSet*) \nonstatic_field(CollectedHeap, _defer_initial_card_mark, bool) \nonstatic_field(CollectedHeap, _is_gc_active, bool) \nonstatic_field(CompactibleSpace, _compaction_top, HeapWord*) \nonstatic_field(CompactibleSpace, _first_dead, HeapWord*) \nonstatic_field(CompactibleSpace, _end_of_live, HeapWord*) \

Page 28: Serviceability Toolsの裏側

トラップ!その1 Linux x86_64環境で動かないことがあります

7003789: PTRACE_GETREGS problems with SA on Linux.○ JDK6u25 、 JDK7 以降なら Fix済み

$ /usr/local/jdk1.6.0_14/bin/jstack -F 8675Attaching to process ID 8675, please wait...Debugger attached successfully.Server compiler detected.JVM version is 14.0-b16Deadlock Detection:

No deadlocks found.

Thread 8693: (state = BLOCKED)Error occurred during stack walking:sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.debugger.DebuggerException: get_thread_regs failed for a lwp

Page 29: Serviceability Toolsの裏側

トラップ!その2 Linux環境でコアイメージを読み込めないこ

とがあります7133122: SA throws

sun.jvm.hotspot.debugger.UnmappedAddressException when it should not○ 全 JDK に影響○ 2012/01 にパッチを出したものの、なかなか入れても

らえない…

$ /usr/local/jdk1.6.0/bin/jstack /usr/local/jdk1.6.0/bin/java core.1249Attaching to core core.1249 from executable /usr/local/jdk1.6.0/bin/java, please wait...Error attaching to core file: Can't attach to the core file

Page 30: Serviceability Toolsの裏側

じゃあ、直してみる OpenJDK  パッチ当て 3 分クッキング

1. OpenJDK のソースを落としてきます2. パッチを当てます3. ビルドします4. libsaproc.so を、使いたい JDK にコピーし

ます

これだけ!

Page 31: Serviceability Toolsの裏側

1. OpenJDK のソース入手 mercurial (hg) を使います

$ hg clone http://hg.openjdk.java.net/jdk8/jdk8複製先ディレクトリ : jdk8全リビジョンを取得中リビジョンを追加中マニフェストを追加中ファイルの変更を追加中666 個のリビジョン (871 の変更を 114 ファイルに適用 ) を追加ブランチ default へ更新中ファイルの更新数 97 、 マージ数 0 、 削除数 0 、 衝突未解消数 0$ cd jdk8/$ sh get_source.sh# Repositories: corba jaxp jaxws langtools jdk hotspot nashorn

リポジトリの clone

forest構成リポジトリの取得

Page 32: Serviceability Toolsの裏側

2.パッチ当て パッチを入手します

CR#7133122 の Comments からコピペserviceability-dev の投稿メールから取得

○ http://mail.openjdk.java.net/pipermail/serviceability-dev/2012-January/005174.html

JDK8 の hotspot で patch します$ patch -p1 < address_mapping.patchpatching file agent/src/os/linux/ps_core.cpatch unexpectedly ends in middle of lineHunk #2 succeeded at 711 with fuzz 1 (offset -1 lines).

Page 33: Serviceability Toolsの裏側

3.ビルド 最近の OpenJDK は configure→make

依存関係は適宜解決してください…

$ chmod a+x configure$ ./configure MILESTONE=TypeSRunning generated-configure.sh

:* Memory limit: 2000 MB* ccache status: installed and in use

$ make:

configure に実行権限が

ついていません

MILESTONE で好きな文字列をバージョンに入れられます

Page 34: Serviceability Toolsの裏側

4. libsaproc の移植 SA のキモです 関数インターフェースがそんなに変わらない

(と思う)ので JDK6/7 へ持って行っても大丈夫(なはず)

libsaproc.so をコンパイルしたものに入れ替え$JAVA_HOME/jre/lib/<CPU> にあります<CPU> には” amd64” や” i386” などが入ります

Page 35: Serviceability Toolsの裏側

コアを食べさせてみる JDK6 GA で試してみました

$ /usr/local/jdk1.6.0/bin/jstack /usr/local/jdk1.6.0/bin/java core.1249Attaching to core core.1249 from executable /usr/local/jdk1.6.0/bin/java, please wait...Debugger attached successfully.Server compiler detected.JVM version is 1.6.0-b105Deadlock Detection:

No deadlocks found.

Thread 1254: (state = BLOCKED)

Thread 1253: (state = BLOCKED) - java.lang.Object.wait(long) @bci=0 (Interpreted frame) - java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=116 (Interpreted frame) - java.lang.ref.ReferenceQueue.remove() @bci=2, line=132 (Interpreted frame) - java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame)

:

動いた!

Page 36: Serviceability Toolsの裏側

なにか忘れてない?http://openjdk.java.net/groups/serviceability/

jcmd

Page 37: Serviceability Toolsの裏側

jcmd

Dynamic Attach と PerfCounter の両面を併せ持つツール

コマンド実装は JVM 側だけで OK !機能追加/改造がラクチン!

Page 38: Serviceability Toolsの裏側

じゃあ、改造してみる OpenJDK   jcmd改造 3 分クッキング

とりあえず、コンパイル済みコードの一覧を出してみます○ CodeCache の内容をダンプしてみます○ CodeCache.print というコマンドにしてみます

1. OpenJDK のソースを落としてきます2. jcmd の実装部を追加します3. ビルドします

これだけ!

Page 39: Serviceability Toolsの裏側

1. OpenJDK のソース入手 省略

Page 40: Serviceability Toolsの裏側

2.改造 下ごしらえ

CodeCache::print_internal が stdout 以外のストリームに出力できるようにします○ hotspot/src/share/vm/code/codeCache.cpp

○ hotspot/src/share/vm/code/codeCache.hpp

static void print_internals(outputStream *tty = tty);

出力先ストリーム追加

void CodeCache::print_internals(outputStream *tty) {

Page 41: Serviceability Toolsの裏側

2.改造 DiagnosticCommand 用クラスの定義

hotspot/src/share/vm/services/diagnosticCommand.hpp

#ifndef PRODUCTclass PrintCodeCacheDCmd : public DCmd {public: PrintCodeCacheDCmd(outputStream* output, bool heap) : DCmd(output,heap) { } static const char* name() { return "CodeCache.print"; } static const char* description() { return "Print compiled methods in CodeCache."; }

static const char* impact() { return “???"; } static int num_arguments() { return 0; } virtual void execute(TRAPS);};#endif

どうしよ…?

Page 42: Serviceability Toolsの裏側

“Impact” とは? 各コマンドの help で表示される部分

JEP 137: Diagnostic-Command Framework定義がものすごく曖昧

○ JVM への影響度合いを Low / Medium / High で分類○ 膨大なスレッドダンプやヒープダンプは深刻、バー

ジョン番号等の取得は大した影響なしと定義http://openjdk.java.net/jeps/137

$ jcmd 1563 help VM.flags:

Impact: Low::

Page 43: Serviceability Toolsの裏側

各コマンドとインパクトコマンド 内容 インパクトhelp コマンドのヘルプ表示 Low

VM.version JVM バージョンの表示 Low

VM.command_line コマンドライン引数の表示 Low

VM.system_properties システムプロパティの表示 Low

VM.flags 非推奨( -XX )オプションの表示 Low

VM.uptime JVM 起動時間の表示 Low

GC.run_finalization ファイナライザの実行 Medium

GC.run GC の実行 Medium

GC.heap_dump ヒープダンプの生成 High

GC.class_histogram クラスヒストグラムの表示 High

GC.class_stats クラス統計情報の表示 High

Thread.print スレッドダンプの表示 Medium

ManagementAgent.start JMX エージェントの起動 No impact

ManagementAgent.start_local JMX エージェントの起動(ローカル限定)

No impact

ManagementAgent.stop JMX エージェントの停止 No impact

safepoint “Depends on Java content.”

Page 44: Serviceability Toolsの裏側

safepoint

いわゆる STWアプリケーションスレッド全停止正式な定義はコチラ

○ http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html#safepoint

jcmd では、 STW を伴うコマンドは最低でもMedium 以上に定義されている模様

Dynamic Attach では以下が safepoint で動作jstackjmap

Page 45: Serviceability Toolsの裏側

結論 実行に STW を伴う JVM の状態によっては処理が高コストになり

うる

上記以外であれば Lowで OK… と、勝手に解釈

Page 46: Serviceability Toolsの裏側

2.改造 CodeCache の全走査になるので、とりあえず

Medium に設定#ifndef PRODUCTclass PrintCodeCacheDCmd : public DCmd {public: PrintCodeCacheDCmd(outputStream* output, bool heap) : DCmd(output,heap) { } static const char* name() { return "CodeCache.print"; } static const char* description() { return "Print compiled methods in CodeCache."; } static const char* impact() { return “Medium"; } static int num_arguments() { return 0; } virtual void execute(TRAPS);};#endif

Page 47: Serviceability Toolsの裏側

2.改造 PrintCodeCacheDCmd の登録

void DCmdRegistrant::register_dcmds()に初期化コードを追加

hotspot/src/share/vm/services/diagnosticCommand.cpp

#ifndef PRODUCT DCmdFactory::register_DCmdFactory( new DCmdFactoryImpl<PrintCodeCacheDCmd>(true, false));#endif

Page 48: Serviceability Toolsの裏側

2.改造 コマンド実行関数の実装

hotspot/src/share/vm/services/diagnosticCommand.cpp

#ifndef PRODUCTvoid PrintCodeCacheDCmd::execute(TRAPS) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::print_internals(output());}#endif

ロック忘れずに!

Page 49: Serviceability Toolsの裏側

3.ビルド 省略ですが…

debug モードでビルド!./configure --with-debug-level=fastdebug

Page 50: Serviceability Toolsの裏側

実行結果 Tomcat7 に jcmd

CATALINA_OPTS に -XX:+Verbose を付加$ ./build/linux-x86_64-normal-server-fastdebug/jdk/bin/jcmd31376 org.apache.catalina.startup.Bootstrap start31390 sun.tools.jcmd.JCmd$ ./build/linux-x86_64-normal-server-fastdebug/jdk/bin/jcmd 31376 CodeCache.print31376:java.util.zip.InflaterInputStream.ensureOpen()V alivejava.lang.Integer.rotateLeft(II)I alivejava.util.zip.ZStreamRef.address()J alivejava.lang.String.charAt(I)C alivejava.lang.String.indexOf(II)I alivesun.misc.Hashing.murmur3_32(I[CII)I alivejava.lang.Object.<init>()V alivesun.nio.cs.UTF_8$Encoder.encode([CII[B)I alivejava.lang.String.equals(Ljava/lang/Object;)Z alivejava.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V alivejava.lang.String.lastIndexOf(II)I alive

:

Page 51: Serviceability Toolsの裏側

何か、新しいツールはないだろうか?

Page 52: Serviceability Toolsの裏側

HeapStatsJVM から OS まで低オーバーヘッドで情報収集!

Page 53: Serviceability Toolsの裏側

HeapStats

障害解析に必要な情報を根こそぎ収集!GC 動作状況、直後のクラスヒストグラムOS リソース( CPU/メモリ)SPECjvm2008 でのオーバーヘッドは 5% 以下

OOME やデッドロックをリアルタイム検知SNMP トラップも送出します

解析は GUI ツールでラクチン!OS ・ Java の情報を横並びで比較可能

Serviceability Toolsのエッセンスも実装!

Page 54: Serviceability Toolsの裏側

こんなにいっぱい見れます!

Page 56: Serviceability Toolsの裏側