阿里雲 ARMS 應用監控重磅支持 Java 21

前言

今年的 9 月 19 日,作爲最新的 LTS (Long Term Support) Java 版本,Java 21 正式 GA,帶來了不少重量級的更新,詳情請參考 The Arrival of Java 21[1]。雖然目前 Java 11 和 Java 17 都還沒有在國內大規模普及,Java 8 依然佔據主流地位,但及時更新 JDK 版本可以爲開發者帶來許多重要的價值,包括應用程序性能和穩定性上的提升,以及可以幫助提升生產力的新功能。作爲亞洲地區最有影響力的可觀測以及 APM 服務提供方,阿里雲 ARMS 團隊也第一時間響應 Java 21 的 GA 發佈,率先對 Java 21 進行了適配,幫助用戶更好的觀測 Java 21 應用!

Java 21 主要新特性

Java 21 帶來了 15 個新特性,包括虛擬線程、分代式 ZGC 等重磅功能,以及其他方面的優化,讓我們先睹爲快,體驗一下這些新特性:

1. 虛擬線程

虛擬線程 (Virtual Threads) 絕對是 Java 21 中最重量級的新特性,此前在 Java 版本中,每一個 java.lang.Thread 對象都只對應一個操作系統內核中的線程,而線程在操作系統又是一種相對昂貴的系統資源:線程的創建、切換、銷燬等操作都需要進入到內核態。在高併發的場景下,如果創建大量線程來處理請求,將會導致多線程被頻繁的掛起和切換,非常消耗系統資源。

虛擬線程則是一種輕量級的用戶態線程,與傳統線程由 OS 調度運行不同,虛擬線程是由 JDK 底層調度運行的,其創建、調度、銷燬等操作全部由用戶空間的庫函數來完成,也就是說虛擬線程與內核中的線程的對應關係是 M:N 的,如圖 1 所示:

圖 1:線程與虛擬線程關係圖

因此,在高併發場景下,創建大量虛擬線程來處理請求的開銷,相比創建大量線程來說將會降低很多。在 Java 程序中,線程與虛擬線程的對比如表 1 所示:

表 1:線程與虛擬線程的對比表

在 Java 21 中,可以通過以下幾種方法創建虛擬線程並運行:

// 方式一:
Thread vt = Thread.startVirtualThread(() -> {});
// 方式二:
Thread.ofVirtual().unstarted(() -> {});
vt.start();
// 方式三:
ThreadFactory tf = Thread.ofVirtual().factory();
Thread vt = tf.newThread(() -> {});
vt.start();
// 方式四:
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
ThreadFactory tf = Thread.ofVirtual().factory();
Thread vt = tf.newThread(() -> {});
executor.submit(vt);

2. 分代式 ZGC

在 Java 21 中,增加了對 ZGC 的分代支持 (Generational ZGC) 以提高垃圾回收的性能。在此之前,ZGC 是沒有分代概念的,每次運行時都會去收集所有的對象,不會考慮對象的年齡。但根據分代收集理論,絕大部分對象都是朝生夕滅的,並且熬過越多次垃圾收集過程的對象會越難死亡。清理年輕代對象需要的資源更少,能清理出更多的內存;反之,清理老年代對象需要的資源更多,能清理出的內存更少。這就意味着,ZGC 可以基於分代收集理論,更進一步的提升垃圾回收效率。於是在 Java 21,分代收集機制被引入,以更頻繁的收集年輕代對象,這對於使用 ZGC 的 Java 應用的性能提升,有非常大的幫助。

在 Java 21 上使用 ZGC,首先需要在 Java 啓動命令中加入 -XX:+UseZGC 選項開啓 ZGC。默認情況下,添加該選項後啓用的是非分代的 ZGC,如需使用分代式 ZGC,則需要再額外添加 -XX:+ZGenerational 選項。

# 使用分代式ZGC
$ java -XX:+UseZGC -XX:+ZGenerational ...

3. 其他特性

除了虛擬線程和分代 ZGC,Java 21 還引入了其他有意思的特性,比如:

  • 允許使用_字符聲明未命名變量,類似 go 語言中的_。
  • 允許使用匿名類與匿名實例的 main 方法,可以利用如下所示的方式執行 main 函數。
void main() {    
    System.out.println("Hello, World!");
}

具體的其它特性,可以參考:http://openjdk.org/projects/jdk/21/

使用 ARMS 監控 Java 21 應用

ARMS 最新的 3.1.0 版本探針中,我們對 Java 21 進行了支持,開發者可以參考此文開啓 Java 21 應用的可觀測之旅。

編寫 Java 21 應用

首先需要下載安裝 JDK 21,可以從 Oracle 等廠商的官網下載安裝,也可以通過 sdkman 等三方工具進行下載安裝。

安裝完 JDK 21 後,可以參考以下代碼,編寫一個簡單的 SpringBoot 3.x 應用,該應用中使用了 Java 21 的 Record Patterns 特性,幫助用戶用簡潔的語法解構 Java 中的 record 對象:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.6</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <groupId>xxx</groupId>
  <artifactId>xxx</artifactId>
  <version>xxx</version>
  <name>xxx</name>

  <properties>
    <java.version>21</java.version>
  </properties>


  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

 

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    record Point(int x, int y) {

    }

    @RestController
    static class DemoController {
        @RequestMapping("/demo")
        String demo(@RequestParam String type) {
            Object object = null;
            if ("record".equals(type)) {
                object = new Point(1, 2);
            } else {
                object = "object";
            }
            return solve(object);
        }

        private String solve(Object object) {
            if (object instanceof Point(int x, int y)) {
                return "Point: " + x + ":" + y;
            }
            return "Invalid Point";
        }
    }
}

接入 ARMS

對於 Java 應用,ARMS 提供了多種便捷接入方式,您可以參考應用監控接入概述[2]進行接入。對於運行在阿里雲容器服務 ACK[3]中的應用,可以擁有最簡單的接入方式:基於 Pilot 模式實現探針的自動注入以及配置,無需修改鏡像,只需要在應用 Yaml 中加入 2 個 Pod Label 就能接入 ARMS。

首先爲 ACK 集羣安裝 ack-onepilot 組件,如圖2所示:

圖 2:安裝 ack-onepilot

安裝完成之後,在 ACK 集羣內創建 Java 應用,並在 pod 的 spec.template.metadata 字段中添加圖 3 中的兩個 Pod 標籤。其中 armsPilotCreateAppName 代表接入到 ARMS 的應用名,可以和 Deployment 名保持一致,armsPilotAutoEnable 設置爲 on 即可。您也可以直接編輯 Deployment 的 Yaml 文件添加 Pod 標籤。

圖 3:添加標籤

應用成功部署後,在 ACK 控制檯上會展示 ARMS 控制檯鏈接,如圖 4 所示,點擊就能跳轉到 ARMS 控制檯。

圖 4:ARMS 控制檯操作選項

Java 啓動應用後,應用也將會打印如圖 5 所示的日誌,說明應用已經掛載上 ARMS 的探針。

圖 5:JDK21 應用啓動日誌

說明:ARMS 對 Java 21 的支持依賴於 3.1.0 版本探針,截至本文發表之日,3.1.0 版本探針還沒有正式發佈,您可以釘釘掃碼加入 ARMS 支持 Java 21 體驗羣,獲取 3.1.0 版本探針。在 3.1.0 版本正式發佈後,您就可以直接在 ARMS 官網下載最新版探針,或者通過通過 Pilot 模式自動獲取 3.1.0 版本探針。

查看監控數據

應用啓動成功後,請求 /demo 接口,將會得到圖 7 所示的響應:

圖 6:/demo 接口響應

在請求完 /demo 接口後,可前往 ARMS 控制檯的應用列表頁面點擊進入應用的監控頁面,如圖 8 所示,或者直接在 ACK 控制檯上通過轉接跳轉進入 ARMS 控制檯。

圖 7:ARMS 控制檯應用列表

可以看到,ARMS 已經成功識別到 Java 21 應用,並收集相關可觀測數據,如圖 9-11 所示,這些觀測數據可幫助用戶快速洞悉系統運行狀況,加速線上問題排查效率,提升業務運行穩定性。更多 ARMS 應用監控的重要功能,比如智能洞察、調用鏈分析、CPU &內存診斷,請參考 ARMS 應用監控幫助文檔[4]

圖 8:ARMS 應用元信息

圖 9:ARMS 應用接口調用信息

圖 10:ARMS 應總覽信息

ARMS 3.X 版本探針新特性一覽

  • 大幅提升了對主流開源框架的埋點覆蓋度,支持對 Reactor Netty 和 Vert.x 等異步框架的完整耗時統計,增加了 OceanBase 的組件支持,同時優化了PostgreSQL、Kafka 等組件的埋點設計,提供了更加精準、更加豐富的指標和 Span 數據。詳情請參考 ARMS 支持的 Java 組件和框架[5]
  • 性能優化,應用接入更加輕量化,更加無感;4C8G 規格的容器場景下,掛載探針帶來的額外 CPU 開銷相較過往版本降低 50%,使用異步框架的場景 CPU 開銷優化幅度達到 65%,性能表現更加良好;啓動時間大幅度優化,探針掛載啓動耗時降低到 5 秒內,通過容器方式接入,init-container 啓動耗時降低到 6 秒內,探針整體啓動耗時縮減 10s+;
  • 支持代碼熱點功能。一般的 Tracing 系統由於只能對主流開源軟件框架中的核心方法進行埋點,當耗時位置出現在 Tracing 埋點缺失的用戶業務邏輯時,在最終的調用鏈中會出現一段較長的耗時無法對應到具體的代碼執行方法,從而導致無法對業務邏輯耗時進行準確的判斷的問題。

圖 11: Tracing 監控盲區示例圖

ARMS 代碼熱點功能在業界知名的開源持續剖析工具 Async Profiler[6]基礎上,通過關聯調用鏈中的 TraceId & SpanId 信息提供了調用鏈級別的 On & Off-CPU 火焰圖,可有效對 Tracing 的監控盲區細節進行還原,幫助用戶診斷各類常見的慢調用鏈問題。

圖 12: ARMS 支持代碼熱點功能效果圖

更多功能介紹和使用細節請參考慢調用鏈診斷利器-ARMS 代碼熱點

更多 ARMS 產品家族的詳細介紹,請參考 ARMS 官方幫助文檔[7]

參考資料:

[1] https://openjdk.org/projects/jdk/21/

[2] https://openjdk.org/jeps/439

[3] https://openjdk.org/jeps/440

[4] https://blogs.oracle.com/java/post/the-arrival-of-java-21

相關鏈接:

[1] The Arrival of Java 21

https://blogs.oracle.com/java/post/the-arrival-of-java-21

[2] 應用監控接入概述

https://help.aliyun.com/zh/arms/application-monitoring/getting-started/overview

[3] 容器服務 ACK

https://www.aliyun.com/product/kubernetes

[4] ARMS 應用監控幫助文檔

https://help.aliyun.com/zh/arms/application-monitoring/product-overview/functional-characteristics

[5] ARMS 支持的 Java 組件和框架

https://help.aliyun.com/zh/arms/application-monitoring/developer-reference/java-components-and-frameworks-supported-by-arms

[6] Async Profiler

https://github.com/async-profiler/async-profiler

[7] ARMS 官方幫助文檔

https://help.aliyun.com/zh/arms/

作者:牧思 & 山獵

原文鏈接

本文爲阿里雲原創內容,未經允許不得轉載。

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