深度探索JFR - JFR詳細介紹與生產問題定位落地 - 3. 各種Event詳細說明與JVM調優策略(2)

2. JAVA 應用相關

2.4. Java Monitor 同步鎖相關

主要是三種 Event:

當進入同步塊,嘗試獲取鎖的時候,產生 JavaMonitorEnter Event;當調用 Object.wait() 進入等待時,會產生 JavaMonitorWait Event;當 鎖升級(另一種說法是鎖膨脹)時,產生 JavaMonitorWait Event。

下面我從網上看到的這張圖,有助於理解這三種事件:

image

  • JavaMonitorEnter(Java Monitor Blocked):進入 Java Monitor Event。當需要進入同步代碼時(字節碼 monitorenter),會產生這個 Event。在 default.jfc 中默認爲啓用的,並且會追蹤堆棧,閾值是 20ms;採集的信息包括:開始時間,持續時間,結束時間,線程,Monitor Address,Monitor Class,之前持有這個 Monitor 的線程。
  • JavaMonitorInflated(Java Monitor Inflated):發生鎖升級的時候的 Event。在 default.jfc 中默認爲啓用的,並且會追蹤堆棧,閾值是 20ms;採集的信息包括:開始時間,持續時間,結束時間,線程,Monitor Address,Monitor Class,鎖升級原因
  • JavaMonitorWait(Java Monitor Wait):調用 Object.wait() 進入等待時,會產生 JavaMonitorWait Event;在 default.jfc 中默認爲啓用的,並且會追蹤堆棧,閾值是 20ms;採集的信息包括:開始時間,持續時間,結束時間,線程,Monitor Address,Monitor Class,喚醒線程Thread, 是否超時, 超時時間。

一般的在默認情況下, JavaMonitorEnter 和 JavaMonitorWait 採集到的在閾值以上的會比較多,一般不會有 JavaMonitorInflated 事件,除非發生 CPU 資源耗盡或者程序不斷 dump 導致一直處於 safepoint。

但是並不是所有的 JavaMonitorEnter 和 JavaMonitorWait Event 都是我們關心的,如何快速找到我們關心的關鍵 Event 呢?

先舉一個 JavaMonitorEnter 的例子:
從事件瀏覽器視角去看, Event 太多了,我們建一個 JavaMonitorEnter Event 的視圖:
image

一般的,我會按照 Monitor class 去分類看,爭用同一個對象鎖一般是同一個業務:
image

image

我們來看第一個計數最多的,點擊這個分類,在下面的列表按照持續需時間倒序,查看線程以及堆棧:
image

發現是因爲本地緩存更新,導致比較慢,這裏本地緩存是讀取的數據庫,讀取的數據比較多,400ms 的比較正常。

我們再來看另一個,Monitor class 爲 java.lang.Object 的:
image

從堆棧上看出是獲取 Lettuce 連接時候,鎖等待了320ms。查看源代碼,發現是連接初始化,導致比較慢,初始化好連接之後沒再出現了。

這裏建議,針對微服務應用,再調高閾值到 50ms。

2.5. Java Thread 相關

四個事件:

  • ThreadStart:線程開始, Thread.start() 時,就會產生這個 Event 記錄
  • ThreadEnd:線程結束,就會產生這個 Event 記錄
  • ThreadPark:一般在 await/notify 的 await 的時候,調用 Unsafe.park() 就會產生這個 Event 記錄
  • ThreadSleep:線程休眠, Thread.sleep()時,就會產生這個 Event 記錄

這些事件我們一般都不關心,Java 線程阻塞與熱點方法和 CPU 消耗等,有其他的 Event,在 default.jfc 中這四個 Event 默認都是採集的,這裏建議關閉這四個 Event 的採集

2.6. 網絡IO socket 相關

  • SocketRead: 網絡讀,在 default.jfc 中,默認啓用,並且會追蹤堆棧,閾值是 20ms;採集的信息包括:開始時間,持續時間,結束時間,線程,遠程 IP,讀取字節大小,是否是流讀取的末尾,遠程 Host,遠程 Port,超時時間
  • SocketWrite: 網絡寫,在 default.jfc 中,默認啓用,並且會追蹤堆棧,閾值是 20ms;採集的信息包括:開始時間,持續時間,結束時間,線程,遠程 IP,寫入字節大小,遠程 Host,遠程 Port

堆棧採集對於這種 Event 很重要,但是對於 Spring Cloud 這樣的框架,調用層次極爲複雜,可能默認採集堆棧深度(64)不夠,需要增大才能看到自己的業務代碼堆棧。但是要注意的一點是:堆棧採集深度,對於性能影響很大,以最壞的情況考慮,可以理解爲增加多少倍的堆棧深度,對性能的影響就提高多少倍。 建議對於常態化的線上監控,堆棧深度最多不超過 128.

2.7. 一些統計數據相關

  • ClassLoaderStatistics: 類加載器相關統計數據,default.jfc 中默認打開,每個 DataChunk 採集一次,一般不會去關心類加載器的統計數據,建議關閉。
  • ClassLoadingStatistics: 類加載相關統計數據,default.jfc 中默認打開,每秒採集一次,一般不會去關心類加載的統計數據,建議關閉。
  • ExceptionStatistics:異常統計數據,default.jfc 中默認打開,每秒採集一次,一般異常通過日誌處理,也不太會關心這個統計數據,建議關閉
  • JavaThreadStatistics:Java 線程數量統計數據,default.jfc 中默認打開,每秒採集一次線程數量,這個還有些參考意義,建議保留默認配置。採集的數據包括:到目前爲止累計線程數量(包括已經 stop 的),當前活動線程數量,守護線程數量,採集時間內峯值線程數量。個人感覺不用每秒採集一次,改成每分鐘即可。
  • ThreadAllocationStatistics:線程分配內存大小統計,包括了線程從開始到現在一共分配的內存大小(包括已釋放的),default.jfc 中默認打開,每個 DataChunk 採集一次,參考意義不大,建議關閉

2. 虛擬機相關 Event

2.1. JVM 啓動參數 Flag 相關

JVM 啓動參數包含很多配置, 同時也可以通過 JVMTI,jcmd 命令等等動態修改這些配置, 如果我們想看這些配置以及修改的時間點,那麼可以打開這些 Event 的採集:

  • BooleanFlag 與 BooleanFlagChange :布爾狀態位以及變化。對應的就是通過類似於通過+``-配置的哪些狀態位,例如-XX:+UseCompressedOops就是打開壓縮對象指針
  • DoubleFlag 與 DoubleFlagChange:double狀態位,例如-XX:InitialRAMPercentage=52.0配置初始內存堆棧佔用比例(只有在沒指定-Xmx-Xms的時候有效)
  • IntFlag 與 IntFlagChange
  • UnsignedIntFlag 與 UnsignedIntFlagChange
  • LongFlag 與 LongFlagChange
  • UnsignedLongFlag 與 UnsignedLongFlagChange
  • StringFlag 與 StringFlagChanged

這個對性能影響是很小的,所以在系統自帶的 default.jfc 中就打開了。我這裏建議還是打開,畢竟基本所有狀態位是可以通過 jcmd 命令修改的,如果有對比需求,對比修改前還有修改後性能影響,那麼狀態位變換時間就很重要了

1.2. 類加載相關

主要包括三種 Event:

  • Class Define: 類定義
  • Class Load: 類加載
  • Class Unload: 類卸載

這些事件我們平常開發一般不會去關心,一般之後開發框架或者定位框架問題的時候,纔會去關心類加載器相關的問題。而且這個用阿里開源的工具 Arthas 更加好用(https://alibaba.github.io/arthas/sc.html):

$ sc -d demo.MathGame
class-info        demo.MathGame
code-source       /private/tmp/arthas-demo.jar
name              demo.MathGame
isInterface       false
isAnnotation      false
isEnum            false
isAnonymousClass  false
isArray           false
isLocalClass      false
isMemberClass     false
isPrimitive       false
isSynthetic       false
simple-name       MathGame
modifier          public
annotation
interfaces
super-class       +-java.lang.Object
class-loader      +-sun.misc.Launcher$AppClassLoader@3d4eac69
                    +-sun.misc.Launcher$ExtClassLoader@66350f69
classLoaderHash   3d4eac69
 
Affect(row-cnt:1) cost in 875 ms.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章