자바 애플리케이션 프로파일링

이 페이지에서는 프로파일링 데이터를 캡처하고 이 데이터를 Google Cloud 프로젝트로 전송하도록 자바 애플리케이션을 수정하는 방법을 설명합니다. 프로파일링에 대한 일반 정보는 프로파일링 개념을 참조하세요.

자바의 프로필 유형:

  • CPU 시간
  • 힙(자바 11 또는 App Engine 표준 환경 필요, 기본적으로 사용 중지됨)
  • 실제 경과 시간(자바 8 App Engine 표준 환경에서는 사용 불가)

지원되는 자바 언어 버전:

  • 자바 8, 11 이상을 위한 HotSpot 기반 JVM(Oracle JDK 및 일부 OpenJDK 빌드)

지원되는 프로파일링 에이전트 버전:

  • 가장 최신 버전의 에이전트가 지원됩니다. 일반적으로 1년이 지난 출시 버전은 지원되지 않습니다. 최근에 출시된 버전의 에이전트를 사용하는 것이 좋습니다.

지원되는 운영체제:

  • Linux. 자바 애플리케이션 프로파일링은 표준 C 라이브러리가 glibc 또는 musl로 구현된 Linux 커널에서 지원됩니다. Linux Alpine 커널의 구성 정보는 Linux Alpine에서 실행을 참조하세요.

지원되는 환경:

Profiler API 사용 설정

프로파일링 에이전트를 사용하기 전에 기본 Profiler API가 사용 설정되어 있는지 확인합니다. Google Cloud CLI 또는 Google Cloud Console을 사용하여 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 사용 설정됨이 표시되어 있으면 API가 이미 사용 설정된 것입니다. 그렇지 않으면 사용 설정 버튼을 클릭합니다.

서비스 계정에 IAM 역할 부여

Google Cloud 리소스에 애플리케이션을 배포하고 있으며 기본 서비스 계정을 사용하고 있고 해당 서비스 계정에 대한 역할 부여를 수정하지 않은 경우 이 섹션을 건너뛰어도 됩니다.

다음 중 하나를 실행하는 경우 서비스 계정에 Cloud Profiler Agent (roles/cloudprofiler.agent)의 IAM 역할을 부여해야 합니다.

  1. 기본 서비스 계정을 사용하고 있지만 역할 부여를 수정한 경우
  2. 사용자가 만든 서비스 계정을 사용하고 있습니다.
  3. 워크로드 아이덴티티를 사용하는 경우 Kubernetes 서비스 계정에 Cloud Profiler 에이전트 역할을 부여합니다.

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 자바 8 런타임 기본 이미지 또는 자바 9 / Jetty 9 런타임 기본 이미지를 사용할 경우 Profiler 에이전트가 사전 설치되므로 에이전트를 설치하기 위한 추가 단계를 수행할 필요가 없습니다.

다른 모든 기본 이미지에서는 에이전트를 설치해야 합니다. 예를 들어 다음 Dockerfileopenjdk: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 파일 경로로 바꿉니다.
  • Dockerfileapp.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

에이전트의 특정 버전을 다운로드하려면 다운로드 명령어에 URL을 전달합니다. 예를 들어 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 에이전트 로드

애플리케이션을 프로파일링하려면 일반적으로 프로그램을 실행할 때처럼 자바를 시작하고 에이전트 구성 옵션을 지정합니다. 에이전트 라이브러리의 경로를 지정하면 라이브러리에 옵션을 전달할 수 있습니다.

App Engine 표준 환경의 경우 에이전트가 자동으로 로드되고 구성됩니다. 프로그램 구성 및 시작에 대한 자세한 내용을 보려면 프로그램 시작으로 건너뛰세요.

에이전트 구성

프로파일링 에이전트를 구성하려면 애플리케이션을 시작할 때 -agentpath 플래그를 포함합니다.

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

위 표현식에서 INSTALL_DIR는 프로파일링 에이전트 경로이고 OPTION1, OPTION2, OPTION3은 에이전트 구성 옵션입니다. 예를 들어 앞의 표현식에서 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와 영역 정보를 수집할 때 사용하는 재시도 정정책을 정의합니다.

기본 정책은 각 시도 사이에 1초를 기다리면서 최대 3회까지 재시도하는 것입니다. 이 정책은 거의 모든 구성에 적합합니다.
-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 기본적으로 애플리케이션의 총 스레드 수가 4,096개를 초과하면 실제 경과 시간 프로필이 수집되지 않습니다. 이 제한은 프로필 수집 중에 스레드 스택을 순회하는 비용을 최소화하기 위함입니다. 서비스에 일반적으로 스레드가 4,096개 이상 있으며 오버헤드 증가를 감수하고 프로파일링 데이터를 수집하려면 이 플래그를 사용하여 한도를 늘립니다.

기본 제한은 스레드 4,096개입니다.
-cprof_enable_heap_sampling 자바 11 이상에서 힙 프로파일링을 사용 설정하려면
-cprof_enable_heap_sampling=true를 설정합니다. 자바 10 이하에는 힙 프로파일링이 지원되지 않습니다.

힙 프로파일링은 기본적으로 중지되어 있습니다.

힙 프로파일링을 사용 설정하면 기본적으로 샘플링 간격이 512KiB로 설정됩니다. 이 간격은 대부분의 애플리케이션에 적합하며 애플리케이션 오버헤드를 0.5% 미만으로 발생시킵니다. 지원되는 샘플링 간격은 256KiB(262,144)~1,024KiB(1,048,576)입니다. 예를 들어 샘플링 간격을 256KiB로 설정하여 샘플링 레이트를 두 배로 늘리려면 다음 에이전트 옵션을 추가합니다.
-cprof_heap_sampling_interval=262144
샘플링 간격을 1,024KiB로 설정하여 샘플링 레이트를 절반으로 줄이려면 다음 에이전트 옵션을 추가합니다.
-cprof_heap_sampling_interval=1048576
이 프로필 유형을 사용 설정하는 경우 애플리케이션을 배포할 때 새 서비스 버전을 지정합니다. 자세한 내용은 특정 프로필 유형의 데이터가 없는 이유가 무엇인가요?를 참조하세요.

서비스 이름 및 버전 인수

Profiler 에이전트를 로드할 때는 서비스 이름 인수와 선택적 서비스 버전 인수를 지정하여 구성합니다.

서비스 이름은 Profiler가 해당 서비스의 모든 복제본에 대한 프로파일링 데이터를 수집할 수 있게 해줍니다. 프로파일러 서비스는 각 서비스 버전 및 영역(zone)의 조합에서 각 서비스 이름에 평균적으로 프로필이 1분에 하나씩 수집되도록 보장합니다.

예를 들어 두 버전이 3개 영역(zone)의 복제본에서 실행 중인 서비스가 있다면 프로파일러가 해당 서비스에 대한 프로필을 평균적으로 1분에 6개씩 만듭니다.

복제본에 서로 다른 서비스 이름을 사용하면 서비스가 불필요하게 자주 프로파일링되므로 오버헤드도 높아집니다.

서비스 이름을 선택할 때 다음에 유의하세요.

  • 애플리케이션 아키텍처에서 서비스를 분명히 나타내는 이름을 선택합니다. 단일 서비스 또는 애플리케이션만 실행하는 경우에는 서비스 이름 선택이 크게 중요하지 않습니다. 하지만 애플리케이션이 마이크로 서비스 집합으로 실행되는 경우와 같은 사례에서는 서비스 이름 선택이 중요합니다.

  • 서비스 이름 문자열에 프로세스 ID와 같은 프로세스 관련 값을 사용하지 않도록 합니다.

  • 서비스 이름 문자열은 다음과 같은 정규 표현식과 일치해야 합니다.

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

imageproc-service와 같은 정적 문자열을 서비스 이름으로 사용하는 것이 좋습니다.

서비스 버전은 선택사항입니다. 서비스 버전을 지정하면 Profiler가 여러 인스턴스의 프로파일링 정보를 집계하여 올바르게 표시할 수 있습니다. 배포된 서비스의 여러 버전을 표시할 때 서비스 버전을 사용할 수 있습니다. Profiler UI를 사용하면 서비스 버전별로 데이터를 필터링할 수 있습니다. 그러면 이전 버전과 새로운 버전의 코드 성능을 비교할 수 있습니다.

서비스 버전 인수 값은 자유 형식 문자열이지만 이 인수 값은 일반적으로 버전 번호와 유사합니다(예: 1.0.0 또는 2.1.2).

프로그램 시작

Compute Engine

일반적으로 프로그램을 실행할 때처럼 자바를 시작하고 에이전트 구성 옵션을 추가합니다.

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 서비스 컨테이너를 수정하여 일반적으로 프로그램을 실행할 때처럼 자바를 시작하고 에이전트 구성 옵션을 추가합니다.

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 런타임 환경

기존 번들 서비스를 사용하지 않는 경우 다음 방법 중 하나를 사용하여 agentpath 플래그를 지정하도록 app.yaml 파일을 수정하여 프로파일러 수집을 사용 설정합니다.

  • 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
    

기존 번들 서비스를 사용하는 경우 다음 방법 중 하나를 사용하여 agentpath 플래그를 지정하도록 appengine-web.xml 파일을 수정하여 프로파일러 수집을 사용 설정합니다.

  • 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

문제해결

이 섹션에는 자바 애플리케이션 프로파일링과 관련된 문제가 나열되어 있습니다. 일반적인 문제에 대한 도움말은 문제 해결을 참조하세요.

동작 원인 솔루션
여러 힙 프로파일러를 사용 설정했으며 프로필 데이터가 없습니다. 여러 힙 프로파일러를 동시에 사용하면 자바에 대한 모든 힙 프로파일링 지원이 사용 중지됩니다. 이는 JVM 제한사항입니다. 1개의 프로파일러를 사용 설정합니다.

Linux Alpine으로 실행

Linux Alpine용 자바 프로파일링 에이전트는 Google Kubernetes Engine 구성에서만 지원됩니다.

Linux Alpine용 최신 자바 프로파일링 에이전트를 설치하려면 프로파일러 에이전트 설치를 참조하세요.

인증 오류

Linux Alpine(예: golang:alpine 또는 alpine)으로 실행되는 Docker 이미지를 사용하면 다음 인증 오류가 표시될 수 있습니다.

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

그런 다음 애플리케이션을 다시 빌드하고 다시 배포해야 합니다.

다음 단계