切換語言為:簡體
把 JDK 升級到 17 的一個必要性理由

把 JDK 升級到 17 的一個必要性理由

  • 爱糖宝
  • 2024-05-24
  • 2148
  • 0
  • 0

背景 TLDR

垃圾回收器的暫停問題對實時響應要求較高的服務來說,一直是個痛點, CMS和G1等主流垃圾回收器的數十毫秒乃至上百毫秒的暫停時間相當致命。 此外,調優門檻也相對較高,需要對垃圾回收器的內部機制有一定的瞭解,才能夠進行有效的調優。 隨著ZGC的出現, 使得這一痛點徹底解決, ZGC 最初在 JDK 11 中作為實驗性功能引入,並在 JDK 15 中宣佈為生產就緒, 由於JDK17纔是比較正式提供給大眾實用的LTS支援版本,而且一部分公司已經在使用,所以本文力推JDK17。

ZGC 作為一款低延遲垃圾收集器,旨在滿足以下目標:

  • 8MB到16TB的堆大小支援

  • 10ms最大GC暫時

  • 最糟糕的情況下吞吐量會降低15%(實測,如果引數配置的問題可能更糟, 官方這個稍微吹牛了點, 說實話就是用CPU換GC時間,也沒有那麼高大上)

升級JDK17的不可拒絕的理由

低延遲的業務需求,毫秒級耗時的GC

據美團的開發說:

在Zeus服務不同叢集中,ZGC在低延遲(TP999 < 200ms)場景中收益較大:

  • TP999:下降12~142ms,下降幅度18%~74%。

  • TP99:下降5~28ms,下降幅度10%~47%。

可以忽略的升級JDK17的理由

  • 新版的SpringBoot 官方最低支援 JDK17,想使用新Spring版本,就得升級

  • JIT 編譯器的增強

  • JDK 17 中的新功能,例如 Sealed 類、Pattern Matching、Records 等

  • 升級到 JDK 17 可以獲得更好的安全性,包括修復的漏洞和強化的安全機制

適用場景

  • 閘道器服務

  • Web API

暫不推薦場景: 定時任務、批次任務、高CPU密集型應用

升級前後對比

話不多說,先看效果

環境:

CPU: 4c
Mem: 6GB

G1引數:

    -Xmx3500m -Xms3500m -XX:+UseG1GC -XX:MaxGCPauseMillis=100
    -XX:G1ReservePercent=10 -XX:ConcGCThreads=2 -XX:ParallelGCThreads=5
    -XX:G1HeapRegionSize=16m -XX:MaxTenuringThreshold=14
    -XX:SurvivorRatio=8

ZGC引數:

    --add-opens=java.base/java.lang=ALL-UNNAMED -Xms3500m -Xmx3500m -XX:ReservedCodeCacheSize=256m -XX:InitialCodeCacheSize=256m -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ConcGCThreads=1 -XX:ParallelGCThreads=3 -XX:ZCollectionInterval=60 -XX:ZAllocationSpikeTolerance=4 -XX:+UnlockDiagnosticVMOptions -XX:-ZProactive  -Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/opt/gc-%t.log:time,tid,tags:filecount=5,filesize=50m

上述兩個引數,均已經在生產環境實驗過, 生產環境的機器是單機擁有1500業務tps的機器

GC耗時對比

把 JDK 升級到 17 的一個必要性理由

從上圖可見, GC耗時是有著質的區別的,這個區別是你用CMS、Parallel GC、 G1 等嘔心瀝血也調校不出來的

這麼短的GC, 可以保證,應用因為JVM層面的卡頓都保持在1ms 以內, 這也是為啥說這點纔是不能拒絕的理由

CPU使用對比

把 JDK 升級到 17 的一個必要性理由

從CPU使用上看, JDK17 相同的程式碼, 比JDK8要高出10 ~ 20%

升級方法

1. JDK選擇或安裝

使用JDK17前必須要安裝JDK17, 對於不同的Linux發行版或者作業系統安裝方法各不相同, 下面給出了一些樣例, 僅供參考。

# ubuntu 安裝jdk17
sudo apt install openjdk-17-jdk

# docker 基礎映象
docker pull openjdk:17-slim
docker pull openjdk:17-jdk-oraclelinux7
FROM openjdk:17-slim

2. JVM 引數調整

有了JDK17後,你已經具備了讓你的Java程式執行在JDK17上的基本條件了,下一步便是配置Jvm 引數如下(有需要的話,可以自行把換行整理下):

    --add-opens=java.base/java.lang=ALL-UNNAMED \
    -Xms1500m -Xmx1500m \
    -XX:ReservedCodeCacheSize=256m \
    -XX:InitialCodeCacheSize=256m \ 
    -XX:+UnlockExperimentalVMOptions \
    -XX:+UseZGC \
    -XX:ConcGCThreads=1 -XX:ParallelGCThreads=2 \
    -XX:ZCollectionInterval=30 -XX:ZAllocationSpikeTolerance=5 \
    -XX:+UnlockDiagnosticVMOptions -XX:-ZProactive \
    -Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/opt/gc-%t.log:time,tid,tags:filecount=5,filesize=50m \
    -XX:+HeapDumpOnOutOfMemoryError \
    -XX:HeapDumpPath=/opt/errorDump.hprof
引數釋義
引數名 引數含義

--add-opens

JDK9模組化後,導致javabase下面的一些基礎包訪問許可權受阻, 需要開放訪問, 預設 設定java.base/java.lang=ALL-UNNAMED 即可

-Xms1500m -Xmx1500m

堆記憶體設定,非常常見,不解釋

-XX:ReservedCodeCacheSize=256m

JIT編譯的程式碼都放在CodeCache中,一般服務64m或128m就已經足夠

-XX:InitialCodeCacheSize=256m

初始code cache大小

-XX:+UnlockExperimentalVMOptions

開啟實驗性質的JVM選項,開啟可以解鎖更多的JVM設定的能力

-XX:+UseZGC

使用ZGC

-XX:ConcGCThreads=1

併發回收垃圾的執行緒。預設是總核數的12.5%,8核CPU預設是1。調大後GC變快,但會多佔用程式執行時的CPU資源

-XX:ParallelGCThreads=2

STW階段使用執行緒數,預設是總核數的60%

-XX:ZCollectionInterval=30

GC週期之間的最大間隔(單位秒)

-XX:ZAllocationSpikeTolerance=5

增大修正係數-XX:ZAllocationSpikeTolerance,更早觸發GC。ZGC採用正態分佈模型預測記憶體分配速率,模型修正係數ZAllocationSpikeTolerance預設值為2

-XX:+UnlockDiagnosticVMOptions -XX:-ZProactive

是否啟用主動回收,預設開啟,這裏的配置表示關閉

-Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/opt/gc-%t.log:time,tid,tags:filecount=5,filesize=50m

GC日誌設定

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/errorDump.hprof

當發生OOM的時候HEAP DUMP 及其配置

參考資料

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.