阿里雲推出 3.x Java 探針,解鎖應用觀測與治理的全新姿勢

作者:張銘輝、泮聖偉

前言

隨着春節大促即將到來,爲了確保線上業務高效穩定地運行,電商企業大多會對旗下關鍵業務應用進行多輪測試。通過模擬線上較高流量的請求,來觀察服務性能的實際表現。以某企業的業務測試報告舉例:

圖 1 壓測報告顯示,成功率非常低,且全局接口成功率都很低

通過報告可以看到:

當應用所承受的流量增加至特定臨界點時,請求成功率大幅下降,導致整個測試周期內平均成功率相當慘淡,僅有 9.89%,並伴隨着較高的響應時間(RT)。經過深入分析,發現這種高失敗率現象普遍存在於所有接口上,並且在整個壓測過程中未顯示出任何迴歸穩定狀態的跡象。

面對這類壓測結果的直觀推斷是應用可能已達到其性能瓶頸。Prometheus 監控所採集的 CPU 使用情況進一步印證了這一假設:應用實例的 CPU 使用率幾乎達到飽和狀態,應用在當前情景下無法處理如此高 TPS(每秒事務數)。該企業採用的優化手段爲:一方面,通過鏈路追蹤(Tracing)數據和 CPU 火焰圖,逐步定位到代碼層面性能瓶頸,並開展針對性優化;另一方面,爲應用集成開源的流量控制防護和熔斷降級組件來應對線上流量的不確定性,並對關鍵業務應用進行擴容處理,進一步增強應用可用性。

圖 2 壓測過程中應用實例 pod 的 CPU 指標

在實際業務場景中類似問題並不少見,並可以總結爲以下兩個挑戰:

  1. 如何定位複雜業務系統中的性能瓶頸?
  2. 如何應對流量的不確定性,保護好我們的服務?

示例中的公司對於以上問題給出了自己的解答:模擬線上流量開展性能測試,以 Tracing 數據 + CPU 火焰圖作爲問題定位依據,通過流控和熔斷降級來保護服務。上述方案在開源領域擁有比較成熟的落地實踐:

  • 使用 OpenTelemetry 的 SDK/Agent 採集 Tracing 數據 [ 1]
  • 使用 Async Profiler 工具生成 CPU 火焰圖 [ 2]
  • 使用 Sentinel 實現流量治理 [ 3]

但實際上,無論是對業務代碼進行改造,還是搭建 OpenTelemetry 服務端用於數據接收,都會帶來一定的成本投入,研發不再能專注於業務代碼開發和維護。那麼,是否有無侵入、自動化方式來解決問題呢?阿里雲推出的全新 3.x 版本 Java 探針爲這些問題帶來了全新回答。

Java 探針(也稱爲 JavaAgent)可以在應用運行態增強應用本身的字節碼,業務應用本身不需要做任何代碼改動即可實現額外能力的擴展[4]。部署在 kubernetes 中的應用,還可以基於 init-container 實現探針自動注入,進一步降低接入成本。

如何定位業務系統性能瓶頸?

正如前文所說,在定位和優化慢調用問題時,除了觀測應用的各個關鍵指標外,還有“兩大法寶”:調用鏈數據(Tracing)和 CPU 火焰圖,可以幫助定位業務調用中耗時較長、CPU 較高的代碼片段然後做對應修復。然而,這“兩大法寶”卻各有自己的“硬傷”:

Tracing 數據常常存在觀測盲區

對 Tracing 而言,其數據一般依賴 Agent/SDK 提供的自動或手動的埋點實現數據採集,然後上報到 Tracing 數據收集端(Collector)存儲,再由展示端的 Dashboard 關聯並展示出來。顯然,一條鏈路的精細程度取決於埋點的顆粒度。但實際上,Tracing 數據的採集也會帶來一定的開銷,並不會無限制地細分粒度,只會對通用框架中的關鍵方法進行埋點。那麼對於某些業務中的高開銷邏輯,往往就可能缺失埋點,從而無法對業務邏輯的耗時進行準確判斷,類似下圖中的埋點缺失問題在調用鏈中經常存在。

圖 3 常見的 Tracing 數據中容易存在未覆蓋埋點導致的觀測盲區

CPU 火焰圖難以幫助定位線上問題

對 CPU 火焰圖而言,可以直觀展現業務應用執行過程中 CPU 密集點。火焰圖中方法棧寬度代表方法執行時長,通過對“寬底座”、“大平頭”的方法開展優化,縮減其調用耗時以達到性能提升效果。然而,許多隱藏的性能問題在測試階段往往不容易暴露出來,但在線上環境卻能顯露無餘。而火焰圖的生成需要花一些時間來採集,當集中於對線上業務進行止血的時候,現場的保存往往有所缺失,畢竟不可能在線上問題發生後先跑個 5 分鐘的火焰圖。這可能會讓整個問題的定位覆盤過程變得更加複雜。

圖 4 常見 CPU 火焰圖中的“大平頭”與“寬底座”

那麼,有沒有一種不需要手動建立密集埋點就能觀測到 Tracing 數據盲區,又可以自動識別慢 trace,並將相關方法棧的 CPU 火焰圖過濾和關聯到對應 Trace 的方法呢?應用實時監控服務(ARMS) 在 3.x 版本 Java 探針中通過 “代碼熱點” 功能給出了答案。

接下來,以解析並遍歷 JSON 數據及調用下游 HTTP 接口場景舉例:

public class HotSpotAction extends AbsAction {

  private RestTemplate restTemplate = new RestTemplate();

  //請求入口方法
  @Override
  public void runBusiness() {
    readFile();
    invokeAPI();
  }

  //執行HTTP調用
  private void invokeAPI() {
    String url = "https://httpbin.org/get";
    String response = restTemplate.getForObject(url, String.class);
  }

   //讀取文件數據並解析
  private double readFile() {
    InputStreamReader reader = new InputStreamReader(
        ClassLoader.getSystemResourceAsStream("data/xxx.json"));
    LinkedList<Movie> movieList = GSON.fromJson(reader, new TypeToken<LinkedList<Movie>>() {
    }.getType());
    double totalCount = 0;
    for (int i = 0; i < movieList.size(); i++) {
      totalCount += movieList.get(i).rating();
    }
    return totalCount;
  }
}

結合下圖,對於上述接口,在 Tracing 系統中找到一條慢調用鏈。可以看到本條調用鏈共計耗時達到了 2649ms,但後兩個 Span 跟第一個 Span 之間存在 2s 多的耗時盲區(這段邏輯對應上述執行 JSON 數據解析),單純依賴於 Tracing 系統,並沒有辦法定位到缺失的 2s 耗時具體發生在哪段代碼中。

圖 5 業務系統的 Tracing 數據,可以看到第二條 span 之前存在一塊觀測盲區

針對上述問題,接入 ARMS 最新版本探針並開啓代碼熱點後,該問題根因定位就變更非常簡單了。僅需單擊調用鏈詳情中的代碼熱點頁籤,可以在右側的火焰圖中看到相比 Tracing 除了左側的 HTTP 相關方法棧(對應 Tracing 中的 HTTP 調用),還包含 com.alibaba.cloud.pressure.memory.HotSpotAction.readFile() 導致的 1.91s 執行耗時:

圖 6 代碼熱點頁籤中的實際展示,可以直觀看到耗時較高的方法棧

圖中左側爲本次調用中所涉及的所有方法所耗時情況列表,右側爲對應方法所有方法棧信息所繪製的火焰圖,其中:

1)"Self" 列顯示方法自身消耗的時間或資源。

  • 這個指標表示方法在自身的調用棧中所消耗時間或資源,不包括其子方法調用所消耗時間或資源。
  • 幫助識別哪些方法在自身內部花費了大量時間或資源。

2)"Total" 列顯示方法及其所有子方法調用所消耗的總時間或資源。

  • 這個指標包括方法自身消耗時間或資源,以及其所有子方法調用所消耗的時間或資源。
  • 幫助瞭解整個方法調用棧中哪些方法所貢獻了最多的時間或資源。

對於如何使用代碼熱點功能生成的火焰圖定位慢調用根因,可以通過重點關注 Self 這一列或者直接看右側火焰圖中底部的較寬火苗從中定位到高耗時的業務方法,較寬火苗其是引發上層耗時高的根源,一般是系統性能的瓶頸所在。

從上圖中不難看到,本文中的慢調用核心原因就是因爲 LinkedList 不具備隨機訪問的能力,在頻繁查的場景下開銷較高,通過將其重構爲 ArrayList 等有索引的 List 實現就可以解決這一問題。其他更多有關代碼熱點的使用細節可以參考該功能相關用戶文檔 [ 5]

如何應對流量的不確定性?

其實在壓測過程中,如果已配置依靠 CPU 指標/流量指標的彈性,爲什麼請求成功率還是會持續劣化?經過分析,從指標到達閾值到新的服務實例就緒過程中其實存在一定的時間間隔(可能是因爲 Java 應用啓動較慢的原因,達到了秒級別的啓動時長),在突增流量場景下出現新服務實例還未就緒,老服務實例就已經過載情況。此時業務成功率大幅下跌原因,一部分是因爲老服務實例過載;另一個原因是,由於原有實例過載,請求處理能力下降,導致大量流量湧入新啓動的服務實例,從而導致新服務實例也因爲過大流量而引起過載,陷入不斷重啓不斷擴容的“最壞情況”。當系統面對突增流量,是否有手段可以有效地保護系統始終處於穩態情況?

那就是微服務引擎(MSE) 的最新特性,自適應過載保護。

圖 7 MSE 自適應過載保護頁面

正常情況下,面對突然到來的流量洪峯(彈性來不及擴容),會導致 CPU 飆升(即系統負載上升),全局接口出現明顯的性能劣化,比如 RT 持續增加、成功率大幅度下跌。

圖 8 開啓過載保護後的大流量壓測情況

Aliyun JavaAgent 3.x 版本提供了自適應過載保護能力,可以有效地保護我們系統。自適應過載保護會在 CPU 使用率到達閾值時調整限流策略,以一定比例進行限流,保障系統負載處於穩定水平,使得全局接口保持較高 RT 及成功率。

圖 9 開啓過載保護後的大流量下接口表現

總成功率 50.99%,在 /xx 接口流量突增後,全局所有接口成功率開始下降,RT 也快速飆升,自適應過載保護生效,成功率逐步上升,RT 也快速回落到正常水平。需要注意的是,壓測中限流也被當成普通異常處理,因此在成功率上僅 50.99%(實際在去除了限流的異常後請求成功率在 80% 左右,從後半段 RT 表現中也可以看到。)

3.x Java 探針,全新的能力矩陣

前文中提到的 “代碼熱點”與“自適應過載保護” 特性,都是以阿里雲推出的全新 3.x Java 探針作爲底座實現的功能,該組件爲您的 Java 應用提供了一整套無侵入的接入方案,深度集成了 OpenTelemetry、Arthas、Sentinel 等多種可觀測與微服務治理組件與方案。幫您快速、無感地接入應用實時監控服務(ARMS)、微服務引擎(MSE)、企業級分佈式應用服務(EDAS)、Serverless 應用引擎(SAE)等雲產品的重要功能。

如何接入 3.x Java 探針

阿里雲 Java 探針提供了多種便捷的接入方式,且可以依據您的需求定製可觀測和服務治理能力的接入與否。您可以參考 ARMS 應用監控接入概述 [ 9] 與 MSE 服務治理應用接入 [ 10] 進行接入。

對於運行在阿里雲容器服務 ACK [ 11] 中的應用,您可以採用最簡單的接入方式:基於 Pilot 模式實現探針的自動注入以及配置,無需修改鏡像,只需要在應用 Yaml 中加入幾個 label 就可以爲 Java 應用接入可觀測或服務治理能力。

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

圖 10 安裝 ack-onepilot

安裝完成之後,在 ACK 集羣內創建Java應用,並在 pod 的 spec.template.metadata 字段中添加幾個 label,您也可以直接編輯 Deployment 的 yaml 文件,在 spec.template.metadata.labels 下爲 pod 添加 label:

如果您需要接入 ARMS 應用實時監控服務,請添加以下兩個 label:

armsPilotAutoEnable: "on"
armsPilotCreateAppName: "${接入到ARMS的應用名}"

如果您需要接入 MSE 微服務治理服務,請添加以下三個 label:

msePilotAutoEnable: "on"
msePilotCreateAppName: "${接入到MSE的應用名}"
mseNamespace: "${接入到MSE的命名空間}"

應用成功部署後,您可以在 ACK 控制檯上看到對應的 Deployment,點擊“ARMS 控制檯”即可跳轉到 ARMS 控制檯查看應用的監控信息。

圖 11 從 ACK 控制檯跳轉到 ARMS 控制檯

如果您的應用接入了 MSE 微服務治理,可以在 ACK 控制檯上點擊更多 > 微服務治理按鈕直接跳轉至 MSE 服務治理控制檯。

圖 12 從 ACK 控制檯跳轉到 MSE 控制檯

版本改動一覽

除“代碼熱點”、“自適應過載保護”功能外,本次 Java 探針中還帶來了其他全新特性:

  • 支持 Java 21 應用的字節碼增強,一個探針可同時支持 Java 8-21 應用的無侵入式可觀測數據採集和微服務治理解決方案。
  • ARMS 數據上報架構全面升級,基於短連接和上報壓縮,進一步濃縮上報數據,數據上報成功率從原有的 99% 提升到 99.99%,提供更加穩定可用的數據採集服務。
  • ARMS 重磅推出慢調用診斷利器——基於調用鏈的代碼熱點功能,提供接口慢調用過程的自動觀測能力,幫助分析代碼執行中的性能瓶頸,詳情請參考使用代碼熱點診斷慢調用鏈的問題 [ 5]
  • ARMS 開展性能優化,應用接入更加輕量化,更加無感;2c4g 雙副本規格的容器場景下,掛載探針帶來的額外 CPU 開銷相較過往版本降低 50%,接近極限 TPS 場景下 CPU 僅增加 10%,使用異步框架的場景 CPU 開銷優化幅度達到 65%,性能表現更加良好;啓動時間大幅度優化,探針掛載啓動耗時降低到 5 秒內,通過容器方式接入,init-container 啓動耗時降低到 6 秒內,探針整體啓動耗時縮減 10s+。詳情請參考ARMS Java探針性能壓測報告 [ 6]
  • ARMS 支持 Vert.x、Reactor-Netty 等異步框架的完整耗時統計,補充了 OceanBase、xxl-job 等組件的自動化埋點,同時對已有的組件如 PostgreSQL、Kafka 等埋點進行優化,提供了更加精準、更加豐富的指標和 Span 數據,詳情請參考 ARMS 支持的 Java 組件和框架 [ 7]
  • MSE 流量防護實現對 RPC 調用行爲的自定義支持,詳情參考配置 MSE 流量防護行爲 [ 8]
  • MSE 流量防護支持自適應過載保護,基於 CPU 指標以及自適應算法自動保護系統不被過大的流量打垮 [ 12]

結語

JavaAgent 技術通過其字節碼增強的特點,可以無侵入地增強Java微服務的功能,爲用戶帶來了全新的產品能力體驗。通過本文的說明,我們可以發現阿里雲 3.x 版本探針不僅引入了激動人心的新特性,而且在使用體驗上也實現了質的飛躍。

  • 在性能方面: 探針掛載啓動耗時降低到 5 秒內,探針整體啓動耗時縮減 10s+ ;掛載探針帶來的額外 CPU 開銷相較過往版本降低 50% ;接近極限 TPS 場景下 CPU 僅增加 10%
  • 在特性方面: 帶來了診斷、治理領域新特性,自適應負載保護、慢調用診斷、Java 21 的支持等。

當然 3.x 系列 Java 探針並不是終點,爲了達成阿里雲上的微服務永遠在線的目標,我們纔剛剛起航。最新的 4.x 版本已經在邀約灰度中,該版本探針完全兼容開源 OpenTracing 協議,新增了自定義線程池的監控,同時提供了更廣的自動埋點支持範圍與更可靠的異步 tracing 能力,歡迎對新版探針感興趣的客戶聯繫進行灰度升級,第一時間使用新探針的特性。

如果您對文中提到的“代碼熱點”特性感興趣,歡迎加入 ARMS 持續剖析(Continuous Profiling)產品能力交流釘釘羣討論。(羣號:2256001967

相關鏈接:

[1] OpenTelemetry 官方網站

https://opentelemetry.io/

[2] Async Profiler 工具

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

[3] 使用 Sentinel 進行流量治理

http://sentinelguard.io/zh-cn/docs/introduction.html

[4] 什麼是 Java agent

https://www.developer.com/design/what-is-java-agent/

[5] 使用代碼熱點診斷慢調用鏈的問題

https://help.aliyun.com/zh/arms/application-monitoring/user-guide/use-code-hotspots-to-diagnose-code-level-problems

[6] Aliyun JavaAgent 性能壓測報告

https://help.aliyun.com/zh/arms/application-monitoring/developer-reference/performance-test-report-of-arms-agent-for-java?spm=a2c4g.11186623.0.0.53f56b77M3aC9f

[7] ARMS 應用監控支持的 Java 組件和框架

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

[8] 配置 MSE 流量防護行爲

https://help.aliyun.com/zh/mse/user-guide/configure-web-behavior-1?spm=a2c4g.11186623.0.0.170a14eabKk9Vm#section-yhc-vub-mk9

[9] ARMS 應用監控接入概述

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

[10] MSE 服務治理應用接入

https://help.aliyun.com/zh/mse/user-guide/application-access-3/?spm=a2c4g.11186623.0.0.62fa26fcWxrSJu

[11] 容器服務 Kubernetes 版 ACK

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

[12] 配置系統防護

https://help.aliyun.com/zh/mse/user-guide/configure-system-protection?spm=a2c4g.11186623.0.i7

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