剖析 Java 應用程式

本頁說明如何修改 Java 應用程式以擷取剖析資料,並將那些資料傳送至您的 Google Cloud專案。如需剖析作業的一般資訊,請參閱剖析概念

Java 適用的剖析類型:

  • CPU 作業時間
  • 堆積 (需要 Java 11 或 App Engine 標準環境,預設為停用)
  • 實際時間 (不適用於 Java 8 App Engine 標準環境)

支援的 Java 語言版本:

  • 適用於 Java 8、11 以上版本的 HotSpot 架構 JVM (包括 Oracle JDK 和部分 OpenJDK 版本)。

支援的剖析代理程式版本:

  • 支援最新版本的代理程式。一般來說,我們不支援一年以上的版本。建議您使用最近發布的代理程式版本。

支援的作業系統:

  • Linux。使用 glibcmusl 實作標準 C 程式庫的 Linux kernel 支援剖析 Java 應用程式。如需 Linux Alpine kernel 專屬的設定資訊,請參閱「在 Linux Alpine 上執行」一文。

支援的環境:

啟用 Profiler API

使用剖析代理程式之前,請確保基礎 Profiler API 已啟用。您可以查看 API 狀態,或視需要使用 Google Cloud CLI 或 Google Cloud 控制台來啟用 API:

gcloud CLI

  1. 如果您尚未在工作站上安裝 Google Cloud CLI,請參閱 Google Cloud CLI 說明文件

  2. 執行下列指令:

    gcloud services enable cloudprofiler.googleapis.com
    

詳情請參閱 gcloud services

Google Cloud 控制台

  1. Enable the required API.

    Enable the API

  2. 如果畫面顯示「API enabled」,代表 API 已啟用。如果未顯示,請按一下「啟用」按鈕。

將 IAM 角色授予服務帳戶

如果您在 Google Cloud 資源上部署應用程式,且使用的是預設服務帳戶,但尚未修改該服務帳戶的角色授予權限,則可略過本節。

如果您執行下列任何操作,就必須為服務帳戶授予 Cloud Profiler 代理程式 (roles/cloudprofiler.agent) 的 IAM 角色:

  1. 您使用預設服務帳戶,但修改了其角色授予權限。
  2. 您使用的是使用者建立的服務帳戶。
  3. 您使用的是 工作負載身分,請將 Cloud Profiler Agent 角色授予 Kubernetes 服務帳戶。

您可以使用Google Cloud 控制台或 Google Cloud CLI,為服務帳戶授予 IAM 角色。舉例來說,您可以使用 gcloud projects add-iam-policy-binding 指令:

gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
    --member serviceAccount:MY_SVC_ACCT_ID@GCP_PROJECT_ID.iam.gserviceaccount.com \
    --role roles/cloudprofiler.agent

使用上述指令前,請先替換以下項目:

  • GCP_PROJECT_ID:您的專案 ID。
  • MY_SVC_ACCT_ID:服務帳戶名稱。

詳情請參閱「管理專案、資料夾和機構的存取權」。

安裝 Profiler 代理程式

Compute Engine

  1. 為 Profiler 代理程式建立安裝目錄,例如 /opt/cprof

     sudo mkdir -p /opt/cprof

  2. storage.googleapis.com 存放區下載代理程式封存,然後將封存解壓縮到安裝目錄:

    wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
    | sudo tar xzv -C /opt/cprof

GKE

修改 Dockerfile,以便為 Profiler 代理程式建立安裝目錄,然後下載代理程式封存,再將封存解壓縮到安裝目錄。

Linux (以 glibc 為基礎的 C 程式庫):

請使用下列安裝指令:

RUN mkdir -p /opt/cprof && \
  wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
  | tar xzv -C /opt/cprof

Linux Alpine (以 musl 為基礎的 C 函式庫):

請使用下列安裝指令:

wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent_alpine.tar.gz \
| tar xzv -C /opt/cprof

彈性環境

使用 Google Java 8 執行階段基本映像檔或 Java 9 / Jetty 9 執行階段基本映像檔時,Profiler 代理程式已預先安裝,因此您不需要採取其他步驟來安裝代理程式。

若是任何其他基本映像檔,則需要安裝代理程式。例如,以下 Dockerfile 包含使用 openjdk:11-slim 映像檔和安裝 Profiler 代理程式的指示,而且其中定義了啟動應用程式時要使用的預設參數:

FROM openjdk:11-slim

COPY . .
RUN  apt-get update \
     && apt-get install wget \
     && rm -rf /var/lib/apt/lists/*

RUN mkdir -p /opt/cprof && \
    wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
    | tar xzv -C /opt/cprof

CMD ["java", "-agentpath:/opt/cprof/profiler_java_agent.so=OPTION1,OPTION2", "-jar", "PATH_TO_YOUR_JAR_FILE"]

如要在 App Engine 彈性環境中使用這個 Dockerfile,您必須執行下列操作:

  • OPTION1OPTION2 改為應用程式所需的代理程式設定值,並將 PATH_TO_YOUR_JAR_FILE 改為 jar 檔案路徑。
  • Dockerfile 放在 app.yaml 檔案所在的目錄中。
  • 修改 app.yaml 檔案以指定自訂執行階段。詳情請參閱「建構自訂執行階段」。

標準環境

使用 Java 執行階段環境時,Profiler 代理程式已預先安裝,因此您不需要採取其他步驟來安裝代理程式。Java 11 以上版本已預先安裝在 /opt/cprof 中。

Google Cloud 外部

  1. 為 Profiler 代理程式建立安裝目錄,例如 /opt/cprof

     sudo mkdir -p /opt/cprof

  2. storage.googleapis.com 存放區下載代理程式封存,然後將封存解壓縮到安裝目錄:

    wget -q -O- https://storage.googleapis.com/cloud-profiler/java/latest/profiler_java_agent.tar.gz \
    | sudo tar xzv -C /opt/cprof

如要列出可供下載的所有代理程式版本,請執行下列指令:

gcloud storage ls gs://cloud-profiler/java/cloud-profiler-*

指令的回應會類似以下:

gs://cloud-profiler/java/cloud-profiler-java-agent_20191014_RC00.tar.gz
gs://cloud-profiler/java/cloud-profiler-java-agent_20191021_RC00.tar.gz
gs://cloud-profiler/java/cloud-profiler-java-agent_20191028_RC00.tar.gz

如要下載特定版本的代理程式,請將其網址傳遞至下載指令。舉例來說,如要下載 2019 年 10 月 28 日建構的代理程式,請使用下列陳述式:

wget -q -O- https://storage.googleapis.com/cloud-profiler/java/cloud-profiler-java-agent_20191028_RC00.tar.gz \
  | sudo tar xzv -C /opt/cprof

初始化期間會記錄代理程式版本。

載入 Profiler 代理程式

如要剖析應用程式,請按照程式正常執行方式啟動 Java,不過要指定 agent-configuration 選項;您要指定代理程式的程式庫路徑,之後即可將選項傳送到該程式庫。

如果是在 App Engine 標準環境,系統會自動載入並設定代理程式。如要進一步瞭解如何設定及啟動程式,請直接跳到「啟動您的程式」一節。

代理程式設定

如要設定剖析代理程式,請在啟動應用程式時加入 -agentpath 標記:

 -agentpath:INSTALL_DIR/profiler_java_agent.so=OPTION1,OPTION2,OPTION3

在這個運算式中,INSTALL_DIR 是剖析代理程式的路徑,而 OPTION1OPTION2OPTION3 是代理程式設定選項。例如,如果您在上一個運算式中將 OPTION1 改為 -cprof_service=myapp,便會將服務名稱設為 myapp。選項數量或其順序並無限制。下表列出了支援的設定選項:

代理程式選項 說明
-cprof_service 如果您的應用程式不是在 App Engine 上執行,您就必須使用這個設定選項來設定服務名稱。如要瞭解服務名稱限制,請參閱「服務名稱和版本引數」。
-cprof_service_version 如果您希望能夠根據服務版本使用 Profiler UI 來分析剖析資料,請使用這個選項設定版本。如要瞭解版本限制,請參閱「服務名稱和版本引數」一節。
-cprof_project_id 在 Google Cloud以外的環境執行時,請使用這個選項來指定您的 Google Cloud 專案 ID。詳情請參閱「剖析在 Google Cloud以外環境執行的應用程式」。
-cprof_zone_name 當您的應用程式在 Google Cloud上執行時,剖析代理程式會透過與 Compute Engine 中繼資料服務通訊來判斷區域。如果剖析代理程式無法與中繼資料服務通訊,您就需要使用這個選項。
-cprof_gce_metadata_server_retry_count
-cprof_gce_metadata_server_retry_sleep_sec
這兩個選項一起定義了 Profiler 代理程式在與 Compute Engine 中繼資料服務通訊時使用的重試政策,收集您的 Google Cloud 專案 ID 和區域資訊。

預設政策是最多重試 3 次,並在兩次嘗試之間等待 1 秒鐘。這項政策已足以滿足大多數設定的需求。
-cprof_cpu_use_per_thread_timers 如要取得最準確的 CPU 作業時間剖析資料,請將這個選項設為 true。使用這個選項會增加每個執行緒的負擔。

預設值為 false。
-cprof_force_debug_non_safepoints 根據預設,除了為所有安全點產生偵錯資訊之外,剖析代理程式也會強制 JVM 為所有 Just-In-Time (JIT) 產生的程式碼產生偵錯資訊。如此將可針對 CPU 作業時間和堆積剖析資料產生最準確的函式和行層級位置資訊,代價則是會產生額外的代理程式負擔。您可以將這個選項設為 false,藉此停止產生 JIT 程式碼的偵錯資訊。

預設值為 true。
-cprof_wall_num_threads_cutoff 根據預設,如果應用程式中的執行緒總數超過 4096 個,系統就不會收集實際時間剖析資料。這個限制可確保在剖析資料收集期間,周遊執行緒堆疊的成本是最低的。如果您的服務通常有 4096 個以上的執行緒,而且您想要以額外的負擔為代價來收集剖析資料,請使用這個標記來提高上限。

預設限制為 4096 個執行緒。
-cprof_enable_heap_sampling 如要針對 Java 11 或更新版本啟用堆積剖析功能,請設定
-cprof_enable_heap_sampling=true。Java 10 以下版本不支援堆積剖析功能。

堆積剖析功能預設為停用。

啟用堆積剖析功能時,系統會將取樣間隔設為 512 KiB。對於大多數應用程式而言,這個間隔已經足夠,而且對應用程式產生的負擔會低於 0.5%。系統支援 256 KiB (262144) 到 1024 KiB (1048576) 的取樣間隔。舉例來說,如要將取樣間隔設為 256 KiB (使取樣率變成兩倍),請新增以下代理程式選項:
-cprof_heap_sampling_interval=262144
同樣地,如要將取樣間隔設為 1024 KiB (使取樣率減半),請新增以下代理程式選項:
-cprof_heap_sampling_interval=1048576
如果您啟用這個設定檔類型,請在部署應用程式時指定新的服務版本。詳情請參閱「為什麼我沒有特定設定檔類型的資料?

服務名稱和版本引數

載入 Profiler 代理程式時,您可指定 service-name 引數及 service-version 引數 (選用) 來加以設定。

「service name」(服務名稱) 可讓 Profiler 收集有關這項服務的所有備用資源剖析資料。分析器服務會針對每個服務名稱的各個版本及區域組合,確保平均每分鐘一個剖析作業的收集頻率。

舉例來說,如果您有一個服務,共有兩個版本在三個區域的備用資源執行,則分析器會為這個服務建立平均每分鐘 6 個剖析作業。

如果您為備用資源使用不同的服務名稱,系統剖析服務的頻率就會比平常更高,相對地負擔也會更大。

選取服務名稱時:

  • 選擇的名稱要能清楚代表應用程式架構中的服務。如果您只執行單一服務或應用程式,服務名稱的選擇就不那麼重要;但如果應用程式是以一組微服務的形式執行,建議就應選擇適當的服務名稱。

  • 請勿在 service-name 字串中使用任何 process-specific 值 (例如 ID)。

  • service-name 字串必須符合這個規則運算式:

    ^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$

使用靜態字串 (如 imageproc-service) 做為服務名稱就是不錯的做法。

「service version」(服務版本) 則為選填項目。如果您指定服務版本,Profiler 可從多個執行個體匯總剖析資訊並正確顯示;這項引數可用來標記服務部署時的不同版本。Profiler UI 可讓您按照服務版本篩選資料,這樣一來,您就能比較新舊版程式碼的運作效能。

service-version 引數的值是任意形式的字串,不過這個引數的值看起來通常和版本號碼類似,例如 1.0.02.1.2

啟動程式

Compute Engine

按照程式正常執行方式來啟動 Java,並且新增 agent-configuration 選項:

java \
    -agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=myapp,-cprof_service_version=1.0.0 \
    JAVA_OPTIONS -jar PATH_TO_YOUR_JAR_FILE PROGRAM_OPTIONS

GKE

將服務容器 Dockerfile 修改為按照程式正常執行方式來啟動 Java,並且新增 agent-configuration 選項:

CMD ["java", \
    "-agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=myapp,-cprof_service_version=1.0.0", \
     "-jar", "PATH_TO_YOUR_JAR_FILE" ]
    

彈性環境

修改 app.yaml 設定檔以設定 PROFILER_ENABLE 環境變數,然後再按照正常方式啟動程式:

env_variables:
   PROFILER_ENABLE: true

詳情請參閱定義環境變數一節。

標準環境

Java 21 執行階段環境

如果您不使用舊版內含服務,請修改 app.yaml 檔案,使用下列任一方法指定 agentpath 標記,啟用剖析器收集功能:

  • 設定 JAVA_TOOL_OPTIONS 環境變數:

    runtime: java21
    env_variables:
      JAVA_TOOL_OPTIONS: "-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true"
    
  • 使用 entrypoint 元素指定 agentpath

    runtime: java21
    entrypoint: java \
      -agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true \
      Main.java
    

如果您使用舊版套裝服務,請修改 appengine-web.xml 檔案,使用下列任一方法指定 agentpath 標記,以便啟用剖析器收集:

  • 設定 JAVA_USER_OPTS 環境變數:

    <?xml version="1.0" encoding="utf-8"?>
    <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <env-variables>
    <env-var name="JAVA_USER_OPTS" value="-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true" />
    </env-variables>
    </appengine-web-app>
  • 設定 CPROF_ENABLE 環境變數:

    <?xml version="1.0" encoding="utf-8"?>
    <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <env-variables>
    <env-var name="CPROF_ENABLE" value="-agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true" />
    </env-variables>
    </appengine-web-app>
  • 使用 entrypoint 元素指定 agentpath

    <?xml version="1.0" encoding="utf-8"?>
    <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
      <entrypoint>
       java
       -agentpath:/opt/cprof/profiler_java_agent.so=-logtostderr,-cprof_enable_heap_sampling=true
      </entrypoint>
    </appengine-web-app>

如果您已設定新的設定檔類型來收集資料,請務必在部署應用程式時指定新的服務版本。如需更多資訊,請參閱「為什麼我沒有特定設定檔類型的資料?

代理程式記錄

剖析代理程式可以報告 App Engine 彈性環境、Compute Engine 和 GKE 的記錄資訊。剖析代理程式支援以下記錄層級:

  • 0:記錄所有訊息。這是預設的記錄層級。
  • 1:記錄警告、錯誤和嚴重錯誤訊息。
  • 2:記錄錯誤和嚴重錯誤訊息。
  • 3:僅記錄嚴重錯誤訊息並停止應用程式。

如要使用預設的記錄層級將標準錯誤寫入記錄,請將 -logtostderr 附加至 -agentpath 設定。

如要將記錄層級設為僅記錄錯誤和嚴重錯誤訊息,請將 -minloglevel=2 附加至 -agentpath 設定。

舉例來說,如要啟用涵蓋錯誤和嚴重錯誤訊息到標準錯誤之間各層級的記錄功能,請將 -logtostderr‑minloglevel=2 附加至 -agentpath 設定:

 java -agentpath:/opt/cprof/profiler_java_agent.so=-cprof_service=myapp,-logtostderr,-minloglevel=2 \
   -jar myApp.jar

疑難排解

本節列出與剖析 Java 應用程式相關的問題。如需常見問題的相關說明,請參閱疑難排解

行為 原因 解決方案
您已啟用多個堆積分析工具,但沒有設定檔資料。 同時使用多個堆積剖析器會停用 Java 的所有堆積剖析支援功能。這是 JVM 的限制。 啟用 1 個分析器。

使用 Linux Alpine 執行

Linux Alpine 的 Java 分析代理程式僅支援 Google Kubernetes Engine 設定。

如要安裝最新的 Linux Alpine Java 分析代理程式,請參閱「安裝分析器代理程式」一文。

驗證錯誤

如果您使用的 Docker 映像檔是透過 Linux Alpine (例如 golang:alpine 或只有 alpine) 來執行,可能會看到下列驗證錯誤:

connection error: desc = "transport: authentication handshake failed: x509: failed to load system roots and no roots provided"

請注意,要查看錯誤,您必須啟用代理程式記錄功能。

以上錯誤指出,透過 Linux Alpine 執行的 Docker 映像檔根據預設並未安裝 SSL 根憑證。如果要讓剖析代理程式與 Profiler API 相互通訊,就必須具有這些憑證。如要解決這項錯誤,請在 Dockerfile 中新增下列 apk 指令:

FROM alpine
...
RUN apk add --no-cache ca-certificates

接著您必須重新建構和重新部署應用程式。

後續步驟