2020年5月31日 星期日

深入理解JVM & G1 GC



大部份的電腦技術書藉像是塊墊腳石,它們能拉升讀者的知識水平,讓人以全新的視野檢視概有的問題。而這本多達200頁的Java技術專書,就是協助讀者跨越JVM的知溝,得以有能力毫無困惑地看完下列這篇G1 GC調校的文章。(https://www.oracle.com/technical-resources/articles/java/g1gc.html)

從事Java程式開發數年,也是最近才著手調整JVM的GC算法參數。因為負責的推薦系統,有高標準的系統回應速度(三秒必須回應),整個系統架構中又含有Java-based的中間層服務。在中間層執行時需要較大Heap記憶體的情境下(十幾GB),如果還使用預設的Parallel GC算法那肯定是不行的(馬上遇到STW/Stop the world的苦果)。因此我改為採用G1 GC算法,它是從JDK7起開始現身,是專為高強度的伺服器端應用程式所設計,強調其能在超大記憶體配置下依舊維持極短GC停頓。

雖然網路上和G1 GC相關的資料多如繁星,卻沒能有系統地整理並釐清眾多GC算法參數之間的脈絡。JVM GC有著多樣的算法(Serial/Parallel/CMS/G1GC),年代型的GC又可細分為Young年代和Old年代。如果沒有按照算法演進順序來一一說明參數功能,光是看到一串名稱大同小異的GC參數組,真的會讓人一頭霧水。恰好本書對症下藥,用循序漸進的章節規劃,擇要介紹常見的GC算法/參數。後半部才正式進入主題,深入說明G1 GC算法的精要。只有極小段落的字句不甚流暢,翻閱時需要另外查詢英文資料補佐理解,讓全書有點缺憾。

不可諱言我從書中學到的知識,讓我解決了前敘提到的推薦系統效能問題,但其中仍然是充滿著不斷間的試誤(Try and Error)過程。藉由檢視gc.log的內容發現遲緩點,嘗試組合不同的GC參數值,調整後觀察運行狀況,中間絲毫沒有捷徑可走。也曾嘗試直接套用網路文章上的「G1 GC最佳參數」設定值,結果等著我的是一次最嚴重的STW停頓(暫停數十秒)。如同作者周明耀所言,GC調校這項任務,會因為不同應用程式的行為、和不同主機間的資源差異,導出截然不同的最適參數組合。在JVM的世界,沒有一組照本宣科的萬用參數組合,只能仰賴程式/系統人員的心力,試圖找出GC運作的「甜蜜點」。

[後記]
最後試出來的JDK 1.7 G1GC參數:
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:GCLogFileSize=50M
-XX:NumberOfGCLogFiles=7
-XX:+UseGCLogFileRotation
-Xloggc:/usr/local/solr/logs/gc.log
-Xmx20g
-Xms20g
-XX:+ParallelRefProcEnabled
-XX:ConcGCThreads=32
-XX:ParallelGCThreads=32
-XX:G1ReservePercent=50
-XX:InitiatingHeapOccupancyPercent=10
-XX:G1HeapWastePercent=1
-XX:G1MixedGCLiveThresholdPercent=80
-XX:MaxGCPauseMillis=900
-XX:+PrintAdaptiveSizePolicy
-XX:+UnlockExperimentalVMOptions
-XX:G1HeapRegionSize=10m
-XX:+UseG1GC

觀察用指令:
# cat gc.log.0 | grep "Eden" -A 0

相關網址:

沒有留言:

張貼留言