摘要:Alibaba Dragonwell 8 提供了不同的方式來使用 JFR 採集性能數據。Alibaba Dragonwell 8 提供了兩個在阿里巴巴的生產環境中進行過廣泛驗證的特性:JWarmUp 和 Java Flight Recorder。

作者 阿里雲智能事業羣 高級技術專家 陸傳勝

阿里巴巴有着最豐富的 Java 應用場景,覆蓋電商,金融,物流等衆多領域,是世界上最大的 Java 用戶之一。2019年3月21日,阿里巴巴在北京阿里雲峯會上正式宣佈開源了Alibaba Dragonwell 8 產品,並建立了Alibaba Dragonwell社區來爲全球 Java 用戶,特別是中文社區的 Java 用戶提供長期支持的 JDK 產品。自宣佈開源以來,Alibaba Dragonwell 8 受到了國內外 Java 開發者的關注,今天這篇文章就來詳解 Alibaba Dragonwell8 的快速安裝和使用,同時列出了參與社區建設的幾種方式,期望爲那些即將安裝及使用 Alibaba Dragonwell 8 的開發者提供參考。

Alibaba Dragonwell 8 介紹

Alibaba Dragonwell 8 是一款免費的OpenJDK 發行版。

它提供長期支持,包括性能增強和安全修復。Alibaba Dragonwell 8 目前支持 X86-64/Linux 平臺,在數據中心大規模 Java 應用部署情況下, 可以大幅度提高穩定性、效率以及性能。Alibaba Dragonwell 8 是 OpenJDK 的下游(friendly fork),使用了和 OpenJDK 一樣的 licensing。Alibaba Dragonwell 8 與 Java SE 標準兼容,用戶可以使用 Alibaba Dragonwell 8 開發和運行 Java 應用程序。此次開源的 Alibaba Dragonwell 8 是阿里巴巴內部 OpenJDK 定製版 AJDK 的開源版本, AJDK 爲在線電商,金融,物流做了結合業務場景的優化,運行在超大規模的,100,000+ 服務器的阿里巴巴數據中心。

安裝 Alibaba Dragonwell 8

目前 Alibaba Dragonwell 8 只支持 Linux x86-64 平臺,並且提供了二進制的預編譯 JDK 包,您可以通過下面的簡單兩步安裝 Alibaba Dragonwell 8。

  • 從 Github 上面 Alibaba Dragonwell 8 項目的下載頁面下載預編譯的二進制 JDK 包。 下載頁面鏈接 https://github.com/alibaba/dragonwell8/releases
  • 將下載下來的 tar 包解壓到目標安裝目錄即可。

安裝完畢後,只需要將應用引用的

JAVA_HOME 指向 Alibaba Dragonwell 8 的安裝目錄就可以使用了。我們以Tomcat8.5.39 版本爲例,爲了讓Tomcat運行在 Alibaba Dragonwell 8上面,

只需要在啓動Tomcat時使用如下命令:

爲了確認是運行在 Alibaba Dragonwell 8上面,可以進一步通過給 java 命令添加 -

showversion 參數來打印 JDK 版本信息加以判斷。

啓動完畢後在 tomcat/logs/catalina.out 文件的開頭,可以看到 Alibaba Dragonwell 8 的版本信息

使用 Alibaba Dragonwell 8 專有特性

在8.0-preview 這個版本中,

Alibaba Dragonwell 8 提供了兩個在阿里巴巴的生產環境中進行過廣泛驗證的特性:JWarmUp 和 Java Flight Recorder。這兩個特性都已經在上游 OpenJDK 社區提交了 JEP 或 patch,在上游合併完成之前,我們希望讓 Alibaba Dragonwell 8 的用戶可以提前使用到這兩個特性。

JWarmUp 快速預熱 Java 應用

OpenJDK 使用了 JIT(Just-in-time) 即時編譯技術,可以動態的把 Java 字節碼編譯成高度優化過機器碼,提高執行效率,但在編譯之前,Java 代碼是以相對低效的解釋器模式執行的。

在應用啓動完成後、業務流量剛進來的短時間內,容易出現的狀況是大量 Java 方法開始被 JIT 編譯,同時業務請求被較慢的解釋器模式執行,最終的結果就是系統負載飆高,可能導致很多用戶請求超時。爲了解決這個問題,之前的很多做法是使用模擬流量來提前預熱應用,JWarmUp 特性提供了一個新的選擇,就是利用 Java 虛擬機前一次執行編譯得記錄來預熱本次應用的執行。

JWarmUp 的原理如下圖所示:

一個典型的應用場景是當應用需要發佈新版本的時候,

  • 首先 JWarmUp 在 Beta 環境(或者有着和生產環境類似流量的其他場景)的單臺機器上短時間執行 Java 應用,並記錄、收集這段時間裏面 JIT 編譯器所做動作的一些元數據。
  • 然後會把這些元數據複製到生產環境的每一臺包含了新版本代碼的機器/容器裏面。
  • 最後在生產環境機器中通過 JWarmUp 參數加載 beta 環境生成的元數據,來指導生產環境的機器在啓動應用的過程中就完成 JIT 預熱。

這樣當用戶請求進入的時候,應用就會處於性能最高的峯值狀態。

收集預熱數據

還以 Tomcat 應用爲例,可以添加下面的命令行參數來在 beta 環境中收集 JIT 編譯時生成的元數據,其中參數

-XX:CompilationWarmUpLogfile= 指定的就是生成的 JWarmUp 文件的路徑。

生成之後可以把這個文件通過 OSS、SFTP 等方式傳輸到生產環境的機器上。

使用記錄的數據來預熱 Java 應用

在生產環境的機器上,只需要使用下面的參數,就可以利用之前的預熱數據來啓動一個新的 Tomcat 實例,其中參數

-XX:CompilationWarmUpLogfile= 制定的就是需要被加載的 JWarmUp 文件路徑,這個文件應該是上一步收集預熱數據時從 beta 環境複製過來的。

使用 Java Flight Recorder 分析 Java 應用性能

JFR(Java Flight Recorder)是 JVM 內置的基於事件的性能分析特性,這是 Oracle JDK7u4 版本開始提供的商業特性,2018 年的時候在 JDK11 上開源了這個特性,但是一直沒有針對 JDK8 版本的支持。

阿里巴巴和 RedHat、Azul、Amazon 等公司一起合作嘗試把這個特性移植回 JDK8上,不過該 patch 暫時還沒有合併回 OpenJDK8u倉庫,我們在 Alibaba Dragonwell 8 中提供了 Alibaba 移植的 JFR 版本,用於幫助用戶提前獲取這方面的支持。

JFR 的用法很簡單,用戶使用命令行參數或者 jcmd 命令控制 HotSpot 輸出性能數據到文件中,然後就能使用開源的 jmc 工具在圖形界面中打開、分析生成的數據文件了。

使用 JFR 收集性能數據

在 Alibaba Dragonwell 8中,默認情況下 JFR 特性是處於關閉的狀態,必須添加命令行參數 -XX:+EnableJFR 來允許使用 JFR 特性。

Alibaba Dragonwell 8 提供了不同的方式來使用 JFR 採集性能數據。

應用可以可以通過命令行參數指定 JFR 再啓動後立馬開始採集數據,這個對於診斷啓動階段的問題會很有幫助。下面的示例命令會在 Java 進程的 JFR 模塊初始化後就開始收集 JFR 數據,持續一分鐘,並且把數據都輸出到名爲rec.jfr 的文件中。

應用也可以只添加 -XX:+EnableJFR ,然後通過 jcmd 命令在應用啓動後的任意時間點開始採集數據,這種情況更加靈活可控,可以滿足隨時隨地進行分析的需求。

以 Tomcat 爲例,啓動 Tomcat 的命令可以是:

當需要收集數據進行分析時,只需要使用目標 Tomcat 進程的 PID 來執行 JFR 對應的 jcmd 命令即可。以 Tomcat 爲例,如果需要在指定時刻開始收集 10 秒的數據,那麼觸發的命令如下:

10 秒之後可以看到生成了 JFR 數據文件/home/my/workdir/rec3.jfr,使用 JMC 即可進行分析。

也可以不指定收集數據的時間,直接啓動 JFR 收集,並且在需要的時候手動把所有生成的數據一次性 dump 到文件,

使用 JMC 分析性能

JFR 記錄 Java 應用性能數據的輸出是一個二進制的文件,我們藉助於 JMC(Java Mission Control) 工具可以在圖形化界面裏面分析具體的性能數據。這個工具是開源產品,沒有包括在 Alibaba Dragonwell 8裏面,

需要到OpenJDK的官方網站下載使用,https://jdk.java.net/jmc/。

請注意,Alibaba Dragonwell8 生成的JFR數據文件需要 7.0 或更高版本的 JMC 工具來分析。

打開 JMC 後,可以點擊左側的詳細類別來詳細分析採樣時間段內發生的各種事件。

診斷調試支持

Alibaba Dragonwell 8 還內置一些方便的診斷特性,主要包括

大對象分配報警

可以通過新的 JVM 參數"

-XX:ArrayAllocationWarningSize=",比如下面代碼中分配了比較大的數組

執行時如果添加 ArrayAllocationWarningSize 選項就會打印出分配該數組時的 Java 堆棧

詳細的 ParNew GC 日誌支持

Alibaba Dragonwell 8 默認使用了

CMS (Concurrent Mark Sweep) 算法,新生代使用了 ParNew 算法,所以內置兩個針對 ParNew GC 日誌的增強

  • 可以通過 jinfo 工具設置 PrintYoungGenHistoAfterParNewGC 選項來在下一次 Young GC 結束的時候打印新生代的對象類型直方圖。命令如下 jinfo-flag+PrintYoungGenHistoAfterParNewGC <pid>

打印完成後,這個選項會被重置回 false 狀態,防止過多的輸出,一個典型的輸出例子如下:

  • 可以通過-XX:+PrintGCRootsTraceTime 來打印處理每一類 GC 根集所花費的詳細 CPU 時間,輸出示例如下:

精簡版 HeapDump 支持

Alibaba Dragonwell 8 的 jmap 工具支持一個新的 dump 選項“mini”可以在做 heapdump 的時候跳過所有的原始類型數組的內容,從而大大減小生成的 heapdump 文件大小,這對於只需要排查類型、對象關係的場景會比較有幫助。

示例命令如下:

參與Alibaba Dragonwell 社區建設

Alibaba Dragonwell 社區提供長期支持的 JDK 版本,用戶可以通過下面途徑獲取支持、參與討論、提出意見。

  • Alibaba Dragonwell 用戶郵件列表: [email protected]
  • Alibaba Dragonwell 項目在 github.com 網站上的 Issues 頁面

參考鏈接

[1] Oracle Java 8 官方文檔

https://docs.oracle.com/javase/8/

[1] OpenJDK 8 項目主頁

https://openjdk.java.net/projects/jdk8u/

[1] Alibaba Dragonwell 8 主頁

https://developer.aliyun.com/opensource/project/alibabadragonwell?spm=5176.215014.963559999.23.70f23801Z02b2d

[2] Alibaba Dragonwell 8 項目

https://github.com/alibaba/dragonwell8

[3] Alibaba Dragonwell 8 用戶指南

https://github.com/alibaba/dragonwell8/wiki/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4Dragonwell8%E7%94%A8%E6%88%B7%E6%8C%87%E5%8D%97

[4] Alibaba Dragonwell 8 發佈說明

https://github.com/alibaba/dragonwell8/wiki/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4Dragonwell8%E5%8F%91%E5%B8%83%E8%AF%B4%E6%98%8E

[5] Alibaba Dragonwell 8 開發指南

https://github.com/alibaba/dragonwell8/wiki/Developer-Guide

相關文章