javaトラブルに備えよう #jjug_ccc #ccc_h2

78
JJUG CCC 2014 Spring H2Javaトラブルに備えよう 日本Javaユーザグループ 上妻 宜人 (あげつま のりと) はてなブログ : n-agetsuma.hatenablog.com

Upload: norito-agetsuma

Post on 25-Jan-2015

28.961 views

Category:

Software


0 download

DESCRIPTION

JJUG CCC 2014 Spring #ccc_h2 のスライドです

TRANSCRIPT

【JJUG  CCC  2014  Spring  H-­‐2】

Javaトラブルに備えよう 日本Javaユーザグループ 上妻 宜人 (あげつま のりと)

はてなブログ : n-agetsuma.hatenablog.com

自己紹介

上妻 宜人 (あげつま のりと)

n  電話の裏側を作っている会社で働いています

n  Java/APサーバの社内技術サポート、トラブル解析

n  Blog 『見習いプログラミング日記』

【JJUG  CCC  2014  Spring  H-­‐2】

Javaトラブルというと  

どんなことを思い浮かべますか?

【JJUG  CCC  2014  Spring  H-­‐2】

Java  Heap  Size  

6me  

-­‐Xmx:  4G

3GB  

2GB  

1GB  

java.lang.OutOfMemoryError:    Java  heap  space

【JJUG  CCC  2014  Spring  H-­‐2】

STOP SLOW 突然の無応答  

or  唐突すぎるスローダウン

【JJUG  CCC  2014  Spring  H-­‐2】

Javaトラブルランキング  (私の感覚調べ)

第1位

OutOfMemoryError  の発生  (Heap、Perm、”unable  to  create  new  na6ve  Thread”)

第2位

スローダウン  /  タイムアウト  (SQL遅延、無限ループ、JTAタイムアウト  など)  

第3位

OSの設定漏れ  (“Too  many  open  files”  など)  

【JJUG  CCC  2014  Spring  H-­‐2】

日常のJavaトラブル対応で  

最も苦労していること

【JJUG  CCC  2014  Spring  H-­‐2】

情報がない、再現もしない  

【JJUG  CCC  2014  Spring  H-­‐2】

GCログがない  クラスヒストグラムがない  

ヒープダンプがない  スレッドダンプがない  

プロファイラがアタッチできない  APログが出てない  

JMXモニタリング情報がない  【JJUG  CCC  2014  Spring  H-­‐2】

トラブル発生に備えて、  

まずは事実の収集が大切です

【JJUG  CCC  2014  Spring  H-­‐2】

本日のテーマ

【JJUG  CCC  2014  Spring  H-­‐2】

Javaトラブルに応じた  

情報収集方法

【JJUG  CCC  2014  Spring  H-­‐2】

本日のコンテンツ

OutOfMemoryErrorに備える  •  GCログによる過度なヒープ消費の発見  

•  クラスヒストグラム  /  ヒープダンプによる解析

スローダウン  /  タイムアウトに備える  •  スレッドダンプ と hprofプロファイラ  

•  JTAタイムアウトの罠  

OSの設定漏れに備える  •  too  many  open  files  

•  unable  to  create  new  na6ve  thread  

【JJUG  CCC  2014  Spring  H-­‐2】

トラブル 第1位

トラブル 第2位

トラブル 第3位

本日のコンテンツ

OutOfMemoryErrorに備える  •  GCログによる過度なヒープ消費の発見  

•  クラスヒストグラム  /  ヒープダンプによる解析

スローダウン  /  タイムアウトに備える  •  スレッドダンプ と hprofプロファイラ  

•  JTAタイムアウトの罠  

OSの設定漏れに備える  •  too  many  open  files  

•  unable  to  create  new  na6ve  thread  

【JJUG  CCC  2014  Spring  H-­‐2】

トラブル 第1位

トラブル 第2位

トラブル 第3位

【JJUG  CCC  2014  Spring  H-­‐2】

Meta  Space

Other    JVM  Mem

Eden Survivor

Old(Tenured) Young(New)

OutOfMemoryとは  :  Javaヒープ振り返り

S0 S1

User agetsuma =  new  User(“Norito Agetsuma”);

java.lang.OutOfMemoryError:  Java  heap  space

ヒープが足りない

【JJUG  CCC  2014  Spring  H-­‐2】

OutOfMemoryErrorに備える

【1.予兆の確認】

Java  Heap  

6me  

-­‐Xmx:  4G

3GB  

2GB  

1GB  

『GCログの出力』

【2.発生時の解析】

『ヒープダンプ』

『クラスヒストグラム』 num    #instances    #bytes      class  name  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        1              10000            250000    java.lang.String        2                  8000            200000    foo.Sample  

Old New S0 S1

.hprofファイル(バイナリ形式)

負荷大

負荷中

25.471:  [GC  (Alloca6on  Failure)      192453K-­‐>98057K(506816K),  0.1321301  secs]  

負荷小

GCログの出力  

【JJUG  CCC  2014  Spring  H-­‐2】

GCログの取得

【JJUG  CCC  2014  Spring  H-­‐2】

java -Xms4g –Xmx4g –XX:MaxMetaspaceSize=512m-Xloggc:${WILDFLY}/standalone/log/ gc.log.`date +%Y%m%d%H%M%S`-XX:+PrintGCDetails -XX:+PrintGCDateStamps-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

改行しない

Java起動オプションにあらかじめ設定する必要がある

GCログ出力の基本設定部分

【JJUG  CCC  2014  Spring  H-­‐2】

java -Xms4g –Xmx4g –XX:MaxMetaspaceSize=512m-Xloggc:${WILDFLY}/standalone/log/ gc.log.`date +%Y%m%d%H%M%S`-XX:+PrintGCDetails -XX:+PrintGCDateStamps-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

改行しない

•  -Xloggc 出力先パスの指定

•  -XX:+PrintGCDetails 詳細レベルでGCロギングする

•  -XX:+PrintGCDateStamps GCログ各行に時刻を出力 (デフォルトはJVM起動からの経過時間のみ)

java -Xms4g –Xmx4g –XX:MaxMetaspaceSize=512m-Xloggc:${WILDFLY}/standalone/log/ gc.log.`date +%Y%m%d%H%M%S`-XX:+PrintGCDetails -XX:+PrintGCDateStamps-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

再起動時のGCログ上書きを防止する

【JJUG  CCC  2014  Spring  H-­‐2】

改行しない

ファイル名:  gc.log.20140510123200

参考:  nekopの日記  GCログを上書きしないためのTips  hjp://d.hatena.ne.jp/nekop/20111017/1318812320

     年 月 日 時 分 秒

GCログのローテーション(JDK6u34〜/7u2〜/8)

【JJUG  CCC  2014  Spring  H-­‐2】

JavaVM gc.log.0  (最大10MB)

サイズローテーション

java -Xms4g –Xmx4g –XX:MaxMetaspaceSize=512m-Xloggc:${WILDFLY}/standalone/log/ gc.log.`date +%Y%m%d%H%M%S`-XX:+PrintGCDetails -XX:+PrintGCDateStamps-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

改行しない

JDK8でGCログも少し進化しています

【JJUG  CCC  2014  Spring  H-­‐2】

Java  HotSpot(TM)  64-­‐Bit  Server  VM  (25.5-­‐b02)  for  linux-­‐amd64  JRE  (1.8.0_05-­‐b13),    built  on  Mar  18  2014  00:29:27  by  "java_re"  with  gcc  4.3.0  20080428  (Red  Hat  4.3.0-­‐8)    Memory:  4k  page,  physical  1536436k(664260k  free),  swap  3080184k(2757976k  free)    CommandLine  flags:    -­‐XX:Ini6alHeapSize=536870912  -­‐XX:MaxHeapSize=536870912    -­‐XX:+PrintGC  -­‐XX:+PrintGCDateStamps                        -­‐XX:+PrintGCDetails                                        -­‐XX:+PrintGCTimeStamps  -­‐XX:+UseCompressedClassPointers  -­‐XX:+UseCompressedOops

•  バージョン/メモリ情報/コマンドライン引数のファイル先頭出力

•  -­‐XX:+PrintGCCause(JDK7u40〜)  のデフォルト化

25.471:  [GC  (Alloca6on  Failure)    192453K-­‐>98057K(506816K)  ...  

GCViewerでログをグラフ化する

【JJUG  CCC  2014  Spring  H-­‐2】

hjps://github.com/chewiebug/GCViewer

GC後メモリ使用量が  一定に保たれていれば正常  

【JJUG  CCC  2014  Spring  H-­‐2】

OutOfMemoryErrorに備える

【1.予兆の確認】

Java  Heap  

6me  

-­‐Xmx:  4G

3GB  

2GB  

1GB  

『GCログの出力』

【2.発生時の解析】

『ヒープダンプ』

『クラスヒストグラム』 num    #instances    #bytes      class  name  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        1              10000            250000    java.lang.String        2                  8000            200000    foo.Sample  

Old New S0 S1

.hprofファイル(バイナリ形式)

負荷大

負荷中

25.471:  [GC  (Alloca6on  Failure)      192453K-­‐>98057K(506816K),  0.1321301  secs]  

負荷小

ヒープダンプの取得

【JJUG  CCC  2014  Spring  H-­‐2】

コマンドラインで取得  

•  JDK6                                    ${JAVA_HOME}/bin/jmap  -­‐dump:live,format=b,file=<filename>    

•  JDK7u4以降  (jmapも継続して有効)        ${JAVA_HOME/bin/jcmd  <pid>  GC.heap_dump  <filename>

OOMエラー時に自動取得  (Java起動オプション)  

•  -­‐XX:+HeapDumpOnOutOfMemoryError  

•  -­‐XX:HeapDumpPath=${WILDFLY}/standalone/log/  

負荷が大きいため、商用ではOOMエラー時自動取得がお勧め

ヒープダンプ解析  :  Eclipse  Memory  Analyzer

【JJUG  CCC  2014  Spring  H-­‐2】

hjp://www.eclipse.org/mat/  からダウンロード

【Leak  Suspects】  ヒープ中に多いオブジェクトの表示  

【JJUG  CCC  2014  Spring  H-­‐2】

OutOfMemoryErrorに備える

【1.予兆の確認】

Java  Heap  

6me  

-­‐Xmx:  4G

3GB  

2GB  

1GB  

『GCログの出力』

【2.発生時の解析】

『ヒープダンプ』

『クラスヒストグラム』 num    #instances    #bytes      class  name  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        1              10000            250000    java.lang.String        2                  8000            200000    foo.Sample  

Old New S0 S1

.hprofファイル(バイナリ形式)

負荷大

負荷中

25.471:  [GC  (Alloca6on  Failure)      192453K-­‐>98057K(506816K),  0.1321301  secs]  

負荷小

クラスヒストグラム

【JJUG  CCC  2014  Spring  H-­‐2】

8761:      num          #instances                  #bytes    class  name  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        1:              3902054            104446080    [B        2:              1003304                64211456    org.hibernate.engine.spi.En6tyEntry        3:              1069377                60752992    [Ljava.lang.Object;        4:              1061657                53156392    [C        5:              1300009                41601968    [[B        6:              1092928                34973696    java.u6l.HashMap$Node        7:              2008549                32136784    java.lang.Integer        8:              1003304                32105728    org.hibernate.engine.internal.En6tyEntryContext        9:              1061269                25470456    java.lang.String      10:            1003304                24079296    net.agetsuma.performancetest.en6ty.Member  

Javaヒープを多く占めているクラスをテキスト形式で取得 

クラスヒストグラム

【JJUG  CCC  2014  Spring  H-­‐2】

8761:      num          #instances                  #bytes    class  name  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐        1:              3902054            104446080    [B        2:              1003304                64211456    org.hibernate.engine.spi.En6tyEntry        3:              1069377                60752992    [Ljava.lang.Object;        4:              1061657                53156392    [C        5:              1300009                41601968    [[B        6:              1092928                34973696    java.u6l.HashMap$Node        7:              2008549                32136784    java.lang.Integer        8:              1003304                32105728    org.hibernate.engine.internal.En6tyEntryContext        9:              1061269                25470456    java.lang.String      10:            1003304                24079296    net.agetsuma.performancetest.en6ty.Member  

Javaヒープを多く占めているクラスをテキスト形式で取得 

JPAエンティティの大量ロード。  JPQL直すか、ScrollableResults使うなどの対処。  

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

【JJUG  CCC  2014  Spring  H-­‐2】

コマンドラインで取得  

•  JDK6                                    ${JAVA_HOME}/bin/jmap  -­‐histo:live  <pid>  

•  JDK7u4以降  (jmapも継続して有効)        ${JAVA_HOME/bin/jcmd  <pid>  GC.class_histogram

CTRL  +  BREAK  (Windows)  /  kill  -­‐3  で標準出力

•  -­‐XX:+PrintClassHistogram  

•  Windowsサービス登録されたTomcatの解析時に便利  

よくあるOOMエラーのパターン  

【JJUG  CCC  2014  Spring  H-­‐2】

よくあるOOMエラーのパターン1  【突出型】

•  ある機能を動かすとOutOfMemoryErrorが発生する

•  多くはDBやファイルからの大量ロードが原因

【JJUG  CCC  2014  Spring  H-­‐2】

青のUsedHeapが急上昇。  

このパターンの解析に欲しい情報

•  エラー時にどんなコードが動いていたか (アプリログ)

•  OutOfMemoryErrorが発生したタイミングのヒープダンプ

【JJUG  CCC  2014  Spring  H-­‐2】

突出型OOMエラー解決への情報収集

•  Java起動オプションに普段から設定しておく

•  OOMエラー発生時に自動的にヒープダンプで状況保存

•  古くからあるJava起動オプション (1.4.2u12, 5u7 〜)

【JJUG  CCC  2014  Spring  H-­‐2】

-­‐XX:+HeapDumpOnOutOfMemoryError  

-­‐XX:HeapDumpPath=${WILDFLY}/standalone/log/

よくあるOOMエラーのパターン2 【じわじわ型】

•  長い時間をかけてOutOfMemoryErrorに至るパターン

•  再現に時間がかかる or 再現しないので厄介

•  原因例: ORマッパキャッシュ/自作キャッシュ/セッション肥大化

【JJUG  CCC  2014  Spring  H-­‐2】

このパターンの解析に欲しい情報

•  時系列のヒープ情報 (何がじわじわ増えているのか)

•  商用のみ再現するケースも多く、OutOfMemoryErrorに至る前に

負荷の大きいヒープダンプを取得するのは困難

【JJUG  CCC  2014  Spring  H-­‐2】

なるべく軽い負荷で  時系列ヒープ情報を比較したい  

【JJUG  CCC  2014  Spring  H-­‐2】

じわじわ型OOMエラー解決への情報収集

『定期的なクラスヒストグラムの収集』  

             JDK6以前 jmap  -­‐histo:live  <pid>  

             JDK7,8                jcmd  <pid>  GC.class_histogram  

•  ヒープダンプと比較して、負荷も軽いため商用で使いやすい

•  cronを利用して定期的に取得、テキストデータをグラフ化

•  増加傾向クラスの利用部分のソースコードをチェック

OSSツール HeapStats  で情報収集する

•  クラスヒストグラムを定期取得&グラフ化するのは面倒

•  HeapStatsではJVMにアタッチ、低オーバヘッドで自動収集

•  専用アナライザでグラフ表示も可能

hjp://icedtea.classpath.org/wiki/HeapStats/jp

クラス別ヒープ使用量の積み上げグラフ 参照ツリー表示

java -Xms?g -Xmx?g -XX:MaxMetaspaceSize=?m

-Xloggc:${WILDFLY}/standalone/log/

gc.log.`date +%Y%m%d%H%M%S`-XX:+PrintGCDetails -XX:+PrintGCDateStamps-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=${WILDFLY}/standalone/log/

まとめ:  OOMエラーに備えたJVMオプション

GC  ログ

ヒープ  ダンプ

【JJUG  CCC  2014  Spring  H-­‐2】

本日のコンテンツ

OutOfMemoryErrorに備える  •  GCログによる過度なヒープ消費の発見  

•  クラスヒストグラム  /  ヒープダンプによる解析

スローダウン  /  タイムアウトに備える  •  スレッドダンプ と hprofプロファイラ  

•  JTAタイムアウトの罠  

OSの設定漏れに備える  •  too  many  open  files  

•  unable  to  create  new  na6ve  thread  

【JJUG  CCC  2014  Spring  H-­‐2】

トラブル 第1位

トラブル 第2位

トラブル 第3位

アプリケーションの応答がない。  

よし、今すぐ再起動で対処だ。

【JJUG  CCC  2014  Spring  H-­‐2】

その問題、高確率で迷宮入りです

【JJUG  CCC  2014  Spring  H-­‐2】

【JJUG  CCC  2014  Spring  H-­‐2】

アプリケーションが遅い、止まった。

よし、スレッドダンプ取得してから、

再起動で対処だ。

スレッドダンプとは

Thread  A

Thread  B

Thread  C

Thread  D

wait wait

wait

ThreadDump  1回目

ThreadDump  2回目

ThreadDump  3回目

•  コマンド実行時のJavaスレッド状態を出力する

•  その瞬間、JavaVMで何が動いていたのか調査するために使う

【JJUG  CCC  2014  Spring  H-­‐2】

スレッドダンプの取得

【JJUG  CCC  2014  Spring  H-­‐2】

•  少なくとも1.4.2にはある  

 kill  -­‐3  <pid>    

•  JDK5以降    ${JAVA_HOME}/bin/jstack  <pid>  

•  JDK7u4以降  (kill  -­‐3  /  jstackも継続して有効)        ${JAVA_HOME/bin/jcmd  <pid>  Thread.print  

•  Windowsサービス登録されたTomcat

画面右下の  Tomcatアイコンをクリック  

スレッドダンプ出力例

"default  task-­‐10"  prio=5  6d=0x00007fef5bb8d000  nid=0xb307    wai6ng  on  condi6on  [0x000000011090a000]        java.lang.Thread.State:  TIMED_WAITING  (parking)          at  sun.misc.Unsafe.park(Na6ve  Method)          -­‐  parking  to  wait  for    <0x00000007fea15470>            at  java.u6l.concurrent.locks.LockSupport.parkNanos  …          〜  省略 〜          at  org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnec6on…              at  slowweb.SlowServlet.processRequest(SlowServlet.java:44)          at  slowweb.SlowServlet.doGet(SlowServlet.java:78)          at  javax.servlet.hjp.HjpServlet.service(HjpServlet.java:687)  

アプリケーション  のスタック

WildFly内部  のスタック  

【JJUG  CCC  2014  Spring  H-­‐2】

スレッドダンプ出力例

"default  task-­‐10"  prio=5  6d=0x00007fef5bb8d000  nid=0xb307    wai6ng  on  condi6on  [0x000000011090a000]  

     java.lang.Thread.State:  TIMED_WAITING  (parking)          at  sun.misc.Unsafe.park(Na6ve  Method)          -­‐  parking  to  wait  for    <0x00000007fea15470>            at  java.u6l.concurrent.locks.LockSupport.parkNanos  …          〜  省略 〜          at  org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnec6on…              at  slowweb.SlowServlet.processRequest(SlowServlet.java:44)          at  slowweb.SlowServlet.doGet(SlowServlet.java:78)          at  javax.servlet.hjp.HjpServlet.service(HjpServlet.java:687)  

アプリケーション  のスタック

WildFly内部  のスタック  

データソースプール枯渇時の接続取得待ちスレッドの例

【JJUG  CCC  2014  Spring  H-­‐2】

可視化ツールその1  『侍』

【JJUG  CCC  2014  Spring  H-­‐2】

hjp://samuraism.jp/samurai/ja/index.html  からダウンロード

スレッドの状態を時系列に表示するのに便利  

スレッドの増加傾向や、ブロックされ具合が一目でわかる

可視化ツールその2 『ThreadLogic』

【JJUG  CCC  2014  Spring  H-­‐2】

hjps://java.net/projects/threadlogic  からダウンロード

怪しいスレッド(確認すべきスレッド)をマーキングしてくれる  

特にWebLogicServer/JRockit向けが精度が高い

よくある突然の無応答トラブル例

•  無限ループ  •  java.u6l.HashMapへのマルチスレッドアクセス  

•  java.u6l.concurrent.ConcurrentHashMapに変更する  

•  SQLの応答待ち  •  コネクションプール枯渇を併発して、全機能停止もある  

•  SQL実行計画を確認し、インデックス付与やSQL書き直し  

•  java.sql.setQueryTimeout(int  seconds)  で予防措置  

【JJUG  CCC  2014  Spring  H-­‐2】

[PostgreSQLの注意]  9.2からsetQueryTimeoutに対応。  〜9.1では『set  statement_6meout  to  <second>』をJDBC実行

ある機能が遅いのはわかったが、  

原因に当たりが付かない場合

【JJUG  CCC  2014  Spring  H-­‐2】

テスト環境で対象機能を動かして  

『hprof』でプロファイリング

【JJUG  CCC  2014  Spring  H-­‐2】

【JJUG  CCC  2014  Spring  H-­‐2】

JDK付属hprofプロファイラ

java  –agentlib:hprof=CPU=samples,file=<出力先指定>

TRACE  301470:          sun.nio.ch.EPollArrayWrapper.epollWait(EPollArrayWrapper.java)          sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)    CPU  SAMPLES  BEGIN  (total  =  145881)  Sun  May  11  12:09:05  2014  rank        self      accum          count            trace  method        1  86.56%  86.56%    126270  301470  sun.nio.ch.EPollArrayWrapper.epollWait        2    7.21%    93.77%        10521    302418  java.net.SocketInputStream.socketRead0        3    1.06%    94.83%            1552    300362  java.lang.ClassLoader.defineClass0  

•  SIGQUIT(kill  -­‐3)または、JavaVM終了時にテキスト出力

【JJUG  CCC  2014  Spring  H-­‐2】

hprof=CPU=samples  の特徴

•  集計対象は『サンプリング時にアクティブなスレッド』のみ  

•  sleep()やwait()による性能遅延は集計対象外

private void sleepAndWait() … { Thread.sleep(5000); wait(5000);}

private List<String> moreLoop() { return Stream.generate(() -> "slow") .limit(100000) .collect(toList());}

【検出できるもの】  

•  長いアクティブスレッド  

•  ループ系性能遅延 等  

【検出できないもの】  

•  sleepスレッド  

•  waitスレッド 等  

【JJUG  CCC  2014  Spring  H-­‐2】

商用での定常的収集にはJFR(有償) Java  Flight  Recorder  (JDK7u40以降)  

hjp://docs.oracle.com/javase/7/docs/technotes/guides/jfr/usingjfr.html

スローダウンと関わりの深い  

タイムアウトへの対処

【JJUG  CCC  2014  Spring  H-­‐2】

【JJUG  CCC  2014  Spring  H-­‐2】

引っかかることの多いタイムアウト

hjp://www.fancyicons.com/free-­‐icon/112/hardware-­‐icon-­‐set/free-­‐server-­‐icon-­‐png/

Webサーバ

mod

_jk

DBサーバ

mod_jk  :  reply_6meout  (worker.proper6es)  •  APサーバからの最大応答待ち時間  (デフォルト無限)  

•  タイムアウト時、ブラウザには502が返る  

APサーバ

select  …

update…

JTAトランザクションタイムアウト  

•  デフォルト値  :  WildFly8  5分 /  WebLogic12c  30秒  

•  タイムアウトを経過しても、止まらないことがある  

【JJUG  CCC  2014  Spring  H-­‐2】

JTAタイムアウト後も止まらないケース

hjp://www.fancyicons.com/free-­‐icon/112/hardware-­‐icon-­‐set/free-­‐server-­‐icon-­‐png/

•  応答のないSQLクエリ受信待ちの場合  

•  同期ソケットI/O中にはinterrrupt()に反応しないのが要因  

•  コネクションプールも浪費する要因なので厄介

"default  task-­‐2”  …        java.lang.Thread.State:  RUNNABLE          at  java.net.SocketInputStream.socketRead0(Na6ve  Method)          at  java.net.SocketInputStream.read(SocketInputStream.java:150)          …            at  org.postgresql.core.v3.QueryExecutorImpl.execute  

【こんなスレッドダンプには注意】

【JJUG  CCC  2014  Spring  H-­‐2】

WildFly8の場合はWARNログがでてきます

WARN    ARJUNA012120:    Thread[…]  not  responding  to  interrupt  when  cancelling  TX  …      -­‐-­‐  worker  marked  as  zombie  and  TX  scheduled  for  mark-­‐as-­‐rollback  

1.    割込みに反応しないので、ゾンビとしてマーキング

WARN  ARJUNA012113:    Transac6onReaper::doCancella6ons  worker  Thread[Transac6on  Reaper  Worker  0,5,main]  missed  interrupt  when  cancelling  TX  0:ffff7f000001:-­‐87f41d4:536f3485:49    

-­‐-­‐  exi6ng  as  zombie  (zombie  count  decremented  to  0)

2.    SQLが返ってきたので、ゾンビスレッドを終了

(ゾンビとしてマーク) (ロールバック確定)

(ゾンビスレッドが終了して、残りのゾンビは0になった)

【JJUG  CCC  2014  Spring  H-­‐2】

SQLクエリタイムアウトを併用して対処

•  JDBC  SQLタイムアウト  •  java.sql.statement.setQueryTimeout(int seconds)•  スレッド割込みではなく、キャンセル要求送信で実現  

•  APサーバ機能  •  WildFly8    『set-­‐tx-­‐query-­‐6meout』の設定  (デフォルト無効)  

•  WebLogic12c      『文タイムアウト』の設定  (デフォルト無限)  

[再びPostgreSQLの注意]  9.2からsetQueryTimeoutに対応。  〜9.1では『set  statement_6meout  to  <second>』をJDBC実行

本日のコンテンツ

OutOfMemoryErrorに備える  •  GCログによる過度なヒープ消費の発見  

•  クラスヒストグラム  /  ヒープダンプによる解析

スローダウン  /  タイムアウトに備える  •  スレッドダンプ と hprofプロファイラ  

•  JTAタイムアウトの罠  

OSの設定漏れに備える  •  too  many  open  files  

•  unable  to  create  new  na6ve  thread  

【JJUG  CCC  2014  Spring  H-­‐2】

トラブル 第1位

トラブル 第2位

トラブル 第3位

Caused  by:  java.io.FileNotFoundExcep6on:  /dev/null  

(Too  many  open  files)

【JJUG  CCC  2014  Spring  H-­‐2】

ファイルディスクリプタが足りない?

init.d配下の起動スクリプトに ulimit –n 65536

/etc/security/limits.conf

【JJUG  CCC  2014  Spring  H-­‐2】

反射的に対処せずに、  

まずは情報収集して事実を確認  

【JJUG  CCC  2014  Spring  H-­‐2】

lsof (list open files) : オープン中ファイル一覧

#  lsof  -­‐p  <java_pid>  COMMAND      PID          USER      FD      TYPE    DEVICE  SIZE/OFF        NODE  NAME  java        14090  agetsuma    337w      REG        253,2              96    524235  /home/test/sandbox/file/0  java        14090  agetsuma    338w      REG        253,2              96    524237  /home/test/sandbox/file/1  java        14090  agetsuma    339w      REG        253,2              96    524239  /home/test/sandbox/file/2  java        14090  agetsuma    340w      REG        253,2              96    524241  /home/test/sandbox/file/3  …

『足りない』のではなく、シンプルにclose()漏れの可能性もある。

事実を把握した上で対処することが大切

【JJUG  CCC  2014  Spring  H-­‐2】

スレッド数上限に達したときも情報収集

【JJUG  CCC  2014  Spring  H-­‐2】

java.lang.OutOfMemoryError  :  unable  to  create  new  thread

•  いきなり /etc/security/limits.conf  の nproc  を拡大しない  

•  スレッドダンプ(jcmd  <pid>  Thread.print) を取得して事実確認  

•  『足りない』が原因とは限らない  

•  余談ですが、このOOMエラーではヒープダンプでません

【JJUG  CCC  2014  Spring  H-­‐2】

本日のまとめ

【JJUG  CCC  2014  Spring  H-­‐2】

『当たり前のことだなぁ』    

思った方も多いと思います  

実際にトラブルに遭遇すると

ググれない場合も少なくないです

一刻も早く回復しなければいけないプレッシャー

ネット接続ができないサーバルーム

【JJUG  CCC  2014  Spring  H-­‐2】

【JJUG  CCC  2014  Spring  H-­‐2】

日頃から素振りをして、  

すぐに実践できると万全です  

GCログとエラー時自動ヒープダンプを有効に

java -Xms?g -Xmx?g -XX:MaxMetaspaceSize=?m

-Xloggc:${WILDFLY}/standalone/log/

gc.log.`date +%Y%m%d%H%M%S`-XX:+PrintGCDetails -XX:+PrintGCDateStamps-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=${WILDFLY}/standalone/log/

GC  ログ

ヒープ  ダンプ

【JJUG  CCC  2014  Spring  H-­‐2】

テスト環境でのOutOfMemoryエラーでは  

積極的にヒープダンプを取得

•  JDK6                                    ${JAVA_HOME}/bin/jmap  -­‐dump:live,format=b,file=<filename>    

•  JDK7u4以降  (jmapも継続して有効)      

 ${JAVA_HOME/bin/jcmd  <pid>  GC.heap_dump  <filename>

【JJUG  CCC  2014  Spring  H-­‐2】

商用などヒープダンプが厳しい場合は

クラスヒストグラムを収集

•  JDK6                                    ${JAVA_HOME}/bin/jmap  -­‐histo:live  <pid>  

•  JDK7u4以降  (jmapも継続して有効)      

 ${JAVA_HOME/bin/jcmd  <pid>  GC.class_histogram

【JJUG  CCC  2014  Spring  H-­‐2】

ヒープ情報収集には HeapStats  もおすすめ

【JJUG  CCC  2014  Spring  H-­‐2】

クラス別ヒープ使用量の積み上げグラフ 参照ツリー表示

hjp://icedtea.classpath.org/wiki/HeapStats/jp    

アプリケーションが止まったら、  

再起動する前にスレッドダンプを収集

【JJUG  CCC  2014  Spring  H-­‐2】

•  少なくとも1.4.2にはある  

 kill  -­‐3  <pid>    

•  JDK5以降    ${JAVA_HOME}/bin/jstack  <pid>  

•  JDK7u4以降  (kill  -­‐3  /  jstackも継続して有効)        ${JAVA_HOME/bin/jcmd  <pid>  Thread.print  

あれ?なんだか遅いな と思ったら

hprofでプロファイリング

【JJUG  CCC  2014  Spring  H-­‐2】

java  -­‐agentlib:hprof=cpu=samples,file=<output.txt>

CPU  SAMPLES  BEGIN  (total  =  145881)  Sun  May  11  12:09:05  2014  rank        self      accum          count            trace  method        1  86.56%  86.56%    126270  301470  sun.nio.ch.EPollArrayWrapper.epollWait        2    7.21%    93.77%        10521    302418  java.net.SocketInputStream.socketRead0        3    1.06%    94.83%            1552    300362  java.lang.ClassLoader.defineClass0  

【JJUG  CCC  2014  Spring  H-­‐2】

#  lsof  -­‐p  <java_pid>  COMMAND      PID          USER      FD      TYPE    DEVICE  SIZE/OFF        NODE  NAME  java        14090  agetsuma    337w      REG        253,2              96    524235  /home/test/sandbox/file/0  java        14090  agetsuma    338w      REG        253,2              96    524237  /home/test/sandbox/file/1  java        14090  agetsuma    339w      REG        253,2              96    524239  /home/test/sandbox/file/2  java        14090  agetsuma    340w      REG        253,2              96    524241  /home/test/sandbox/file/3  …

『too many open files』が出たら、

すぐに拡張せずに lsof で事実の確認

トラブル解決には  

『事実』の積み重ねが大切  

【JJUG  CCC  2014  Spring  H-­‐2】 OracleとJavaは、Oracle    Corpora6on    及びその子会社、関連会社の米国及びその他の国における登録商標です。  文中の社名、商品名等は各社の商標または登録商標である場合があります。