Python 애플리케이션 프로파일링

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

Python의 프로파일 유형:

  • CPU 시간
  • 실제 경과 시간(기본 스레드)

지원되는 Python 언어 버전:

  • Python 3.6 이상

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

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

지원되는 운영체제:

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

지원되는 환경:

Profiler API 사용 설정

프로파일링 에이전트를 사용하기 전에 기본 Profiler API가 사용 설정되어 있는지 확인합니다. Cloud SDK gcloud 명령줄 도구 또는 Cloud Console을 사용하여 API 상태를 확인하고 필요한 경우 사용 설정할 수 있습니다.

Cloud SDK

  1. 워크스테이션에 Cloud SDK를 아직 설치하지 않은 경우 Google Cloud SDK를 참조합니다.

  2. 다음 명령어를 실행합니다.

    gcloud services enable cloudprofiler.googleapis.com
    

자세한 내용은 gcloud services를 참조하세요.

Cloud Console

  1. API 및 서비스 대시보드로 이동합니다.

    API 및 서비스로 이동

  2. API에 액세스하는 데 사용할 프로젝트를 선택합니다.

  3. API 및 서비스 추가 버튼을 클릭합니다.

    API 및 서비스 추가

  4. Profiler API를 검색합니다.

  5. 검색 결과에서 Cloud Profiler API를 선택합니다.

    Cloud Profiler API가 표시되지 않으면 Stackdriver Profiler API를 선택합니다.

  6. API 사용 설정됨이 표시되어 있으면 API가 이미 사용 설정된 것입니다. 그렇지 않으면 사용 설정 버튼을 클릭합니다.

Cloud Profiler 사용

Python 사용 권장사항은 Python 개발 환경 설정을 참조하세요.

Compute Engine

Compute Engine에서 다음을 수행합니다.

  1. C/C++ 컴파일러 및 개발 도구를 설치합니다.

    sudo apt-get install -y build-essential
    
  2. pip를 설치합니다.

    sudo apt-get install -y python3-pip
    
  3. Profiler 패키지를 설치합니다.

    pip3 install google-cloud-profiler
    
  4. googlecloudprofiler 모듈을 가져오고 가능한 빨리 googlecloudprofiler.start 함수를 초기화 코드에서 호출합니다.

    import googlecloudprofiler
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service='hello-profiler',
                service_version='1.0.1',
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

    start 함수에 service 매개변수를 지정해야 합니다. Profiler 인터페이스에서 애플리케이션 버전을 기준으로 필터링하려면 service_version 매개변수를 지정합니다. 문제해결 및 예외 정보는 문제해결을 참조하세요.

GKE

GKE에서 다음을 수행합니다.

  1. Dockerfile을 수정하여 Profiler 패키지를 설치합니다.

    FROM python:3
    ...
    RUN apt-get update && apt-get install -y build-essential python3-pip
    RUN pip3 install google-cloud-profiler
    
  2. googlecloudprofiler 모듈을 가져오고 가능한 빨리 googlecloudprofiler.start 함수를 초기화 코드에서 호출합니다.

    import googlecloudprofiler
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service='hello-profiler',
                service_version='1.0.1',
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

    start 함수에 service 매개변수를 지정해야 합니다. Profiler 인터페이스에서 애플리케이션 버전을 기준으로 필터링하려면 service_version 매개변수를 지정합니다. 문제해결 및 예외 정보는 문제해결을 참조하세요.

가변형 환경

App Engine 가변형 환경에서 다음을 수행합니다.

  1. requirements.txt 파일에 google-cloud-profiler를 추가합니다.

  2. googlecloudprofiler 모듈을 가져오고 가능한 빨리 googlecloudprofiler.start 함수를 초기화 코드에서 호출합니다.

    import googlecloudprofiler
    
    # Profiler initialization. It starts a daemon thread which continuously
    # collects and uploads profiles. Best done as early as possible.
    try:
        # service and service_version can be automatically inferred when
        # running on App Engine. project_id must be set if not running
        # on GCP.
        googlecloudprofiler.start(verbose=3)
    except (ValueError, NotImplementedError) as exc:
        print(exc)  # Handle errors here
    

App Engine의 경우 serviceservice_version은 운영 환경에서 파생됩니다. 문제해결 및 예외 정보는 문제해결을 참조하세요.

표준 환경

Python 3 런타임 환경을 사용해야 하는 App Engine 표준 환경의 경우 다음을 수행합니다.

  1. requirements.txt 파일에 google-cloud-profiler를 추가합니다.

  2. googlecloudprofiler 모듈을 가져오고 가능한 빨리 googlecloudprofiler.start 함수를 초기화 코드에서 호출합니다.

    import googlecloudprofiler
    
    # Profiler initialization. It starts a daemon thread which continuously
    # collects and uploads profiles. Best done as early as possible.
    try:
        # service and service_version can be automatically inferred when
        # running on App Engine. project_id must be set if not running
        # on GCP.
        googlecloudprofiler.start(verbose=3)
    except (ValueError, NotImplementedError) as exc:
        print(exc)  # Handle errors here
    

App Engine의 경우 serviceservice_version은 운영 환경에서 파생됩니다. 문제해결 및 예외 정보는 문제해결을 참조하세요.

start 함수

googlecloudprofiler.start 함수는 프로필을 계속 수집 및 업로드하는 데몬 스레드를 만듭니다. start를 애플리케이션에서 가능한 한 빨리 한 번만 호출해야 합니다.

매개변수 설명
service1 (필수) 프로파일링할 서비스의 이름. 서비스 이름에 대한 제한사항은 서비스 이름 및 버전 인수를 참조하세요.
service_version1 (선택사항) 프로파일링할 서비스의 버전. 서비스 버전에 대한 제한사항은 서비스 이름 및 버전 인수를 참조하세요.
verbose (선택사항) 로깅 수준. 로깅 수준에 대한 자세한 내용은 에이전트 로깅을 참조하세요.

기본값은 0(오류)입니다.
project_id2 (선택사항) Google Cloud 프로젝트 ID입니다.
disable_cpu_profiling (선택사항) CPU 시간 프로파일링을 중지하려면 disable_cpu_profiling=True를 설정합니다.

이 매개변수는 Python 버전 3.2 이상에서만 지원됩니다. 다른 모든 Python 버전에서는 CPU 시간 프로파일링이 지원되지 않으며 이 매개변수가 무시됩니다.

기본값은 False입니다.
disable_wall_profiling (선택사항) 실제 경과 시간 프로파일링을 중지하려면 disable_wall_profiling=True를 설정합니다.

이 매개변수는 Python 3.6 이상에서 지원됩니다. 다른 모든 Python 버전에서는 실제 경과 시간 프로파일링이 지원되지 않으며 이 매개변수가 무시됩니다.

실제 경과 시간 프로파일링이 사용 설정된 경우 start 함수에 대한 제한사항은 제한사항을 참조하세요.

기본값은 False입니다.

1 Compute Engine 및 GKE에만 해당됩니다. App Engine의 경우 환경에서 값이 파생됩니다.
2 Google Cloud의 경우 환경에서 값이 파생됩니다. Google Cloud 이외의 환경에서는 값을 제공해야 합니다. 자세한 내용은 Google Cloud 외부에서 실행되는 애플리케이션 프로파일링을 참조하세요.

데이터 분석

Profiler가 데이터를 수집하면 개발자가 Profiler 인터페이스를 사용하여 이 데이터를 보고 분석할 수 있습니다. 이 인터페이스를 사용하기 시작하려면 Profiler 인터페이스 열기를 참조하세요.

서비스 이름 및 버전 인수

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

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

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

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

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

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

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

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

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

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

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

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

에이전트 로깅

기본적으로 프로파일링 에이전트는 심각도 수준이 error인 메시지를 로깅합니다. 심각도 수준이 더 낮은 메시지를 로깅하도록 에이전트를 구성하려면 에이전트를 시작할 때 verbose 매개변수를 지정합니다. verbose에는 다음 4개 값이 지원됩니다.

  • 0: 오류
  • 1: 경고
  • 2: 정보 제공
  • 3: 디버그

start 호출에서 verbose 매개변수를 1로 설정하면 심각도 수준이 Warning 또는 Error인 메시지가 로깅되고 InformationalDebug 메시지는 무시됩니다.

모든 메시지를 로깅하려면 에이전트를 시작할 때 verbose3으로 설정합니다.

googlecloudprofiler.start(service='service_name', verbose=3)

문제 해결

이 섹션에는 Python 애플리케이션 프로파일링과 관련된 제한사항, 예외, 알려진 문제가 나와 있습니다. 일반적인 문제에 대한 도움말은 문제 해결을 참조하세요.

제한사항

프로필 유형 제한 및 한도
실제 경과 시간
  • 기본 스레드 프로파일링만 해당됩니다.
  • 프로필 start 함수는 기본 스레드에서 호출되어야 합니다.
  • Profiler 신호 처리기는 기본 스레드에서만 실행됩니다. 기본 스레드를 실행할 수 없으면 프로파일링 데이터가 캡처되지 않습니다.

예외

오류 원인 해결책
start 중에 NotImplementedError 발생 애플리케이션이 Linux 이외 환경에서 실행되었습니다.
  • Linux 환경에서 애플리케이션을 실행합니다.
start 중에 ValueError 발생 start 함수 인수가 잘못되었습니다. CPU 시간 프로파일링과 실제 경과 시간 프로파일링이 모두 중지된 경우 환경 변수와 인수 또는 프로파일링에서 필요한 정보를 확인할 수 없습니다.
  • 서비스 이름과 버전이 서비스 이름 및 버전 인수에서 정의된 요구사항을 충족하는지 확인합니다.
  • 실제 경과 시간 프로파일링이 사용 설정된 경우 기본 스레드에서 start가 호출되는지 확인합니다.
  • 지원되는 Python 버전을 사용하고 있고 CPU 시간 프로파일링 또는 실제 경과 시간 프로파일링이 사용 설정되었는지 확인합니다. 자세한 내용은 start 함수를 참조하세요.
  • Google Cloud 외부에서 실행 중인 경우 project_id 매개변수를 start로 지정했는지 확인합니다. 자세한 내용은 start 함수를 참조하세요.

알려진 문제

동작 원인 해결책
프로필 데이터가 전혀 없거나 새 프로필 유형을 사용 설정했는데 프로필 데이터를 찾을 수 없습니다. 일반적인 원인은 구성과 관련되어 있습니다. 문제 해결을 참조하세요.
uWSGI를 사용 중이며 모든 프로세스에 CPU 시간과 실제 경과 시간 데이터가 없습니다.

uWSGI가 여러 작업자를 사용하여 요청을 처리하는 경우 기본 동작은 기본('마스터') 프로세스에서만 애플리케이션 초기화를 수행하는 것입니다. 포크된 프로세스는 초기화 시퀀스를 수행하지 않습니다.

애플리케이션의 초기화 시퀀스(예: Django 애플리케이션의 AppConfig.ready())에 프로파일링 에이전트를 구성하면 프로파일링 에이전트가 포크된 프로세스에 대해서는 구성되지 않습니다.

모든 작업자 프로세스에서 애플리케이션 초기화를 수행하려면 lazy-apps 플래그를 true로 설정합니다.

관련 문제는 이 표의 다음 주제를 참조하세요.

uWSGI를 사용 중이며 실제 경과 시간 데이터는 없지만 CPU 시간 프로필 데이터는 있습니다.

실제 경과 시간 프로파일러는 Python 신호 모듈에 따라 다릅니다. Python 인터프리터가 스레드 지원과 함께 컴파일되면 기본 구성이 포크된 프로세스의 커스텀 신호 처리를 사용 중지합니다.

uWSGI 애플리케이션의 경우 py-call-osafterfork 플래그를 true로 설정하여 커스텀 신호 처리를 사용 설정합니다.

관련 문제는 이 표의 이전 주제를 참조하세요.

프로파일러를 사용 설정한 후에는 오류 로그에 다음과 같은 새 항목이 포함됩니다.

BlockingIOError: [Errno 11] Resource temporarily unavailable Exception ignored when trying to write to the signal wakeup fd

GitHub 문제

신호 wakeup 파일 설명자(signal.set_wakeup_fd)로 등록된 애플리케이션. 기본적으로 파일 설명자의 버퍼가 채워지면 stderr에 경고가 로깅됩니다.

Cloud Profiler는 프로필을 수집할 때 높은 빈도로 신호를 트리거합니다. 이 동작으로 인해 파일 설명자의 버퍼가 가득 찰 수 있습니다.

신호가 손실될 때 애플리케이션을 안전하게 실행할 수 있으면 Cloud Profiler를 사용할 수 있습니다. Python 3.7 이상을 사용 중이고 경고 메시지를 사용 중지하려면 warn_on_full_buffer=Falsesignal.set_wakeup_fd에 매개변수로 전달합니다.

신호가 손실될 때 애플리케이션을 안전하게 실행할 수 없으면 Cloud Profiler 사용을 중지하는 것이 좋습니다. 계속 사용하면 신호 번호가 손실되고 오류 로그에 항목이 과도하게 표시될 수 있습니다.

Linux Alpine으로 실행

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

Python 프로파일링 에이전트를 빌드하려면 build-base 패키지를 설치해야 합니다. 최종 Alpine 이미지에 추가 종속 항목을 설치하지 않고 Alpine에서 Python 프로파일링 에이전트를 사용하려면 2단계 빌드를 사용하고 첫 번째 단계에서 Python 프로파일링 에이전트를 컴파일합니다. 예를 들어 다음 Docker 이미지는 다단계 빌드를 사용하여 Python 프로파일링 에이전트를 컴파일하고 설치합니다.

FROM python:3.7-alpine as builder

# Install build-base to allow for compilation of the profiling agent.
RUN apk add --update --no-cache build-base

# Compile the profiling agent, generating wheels for it.
RUN pip3 wheel --wheel-dir=/tmp/wheels google-cloud-profiler

FROM python:3.7-alpine

# Copy over the directory containing wheels for the profiling agent.
COPY --from=builder /tmp/wheels /tmp/wheels

# Install the profiling agent.
RUN pip3 install --no-index --find-links=/tmp/wheels google-cloud-profiler

# Install any other required modules or dependencies, and copy an app which
# enables the profiler as described in "Enable the profiler in your
# application".
COPY ./bench.py .

# Run the application when the docker image is run, using either CMD (as is done
# here) or ENTRYPOINT.
CMD python3 -u bench.py

인증 오류

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

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

다음 단계

Profiler 그래프와 컨트롤에 대한 자세한 내용은 Cloud Profiler 인터페이스 사용을 참조하세요. 고급 정보는 다음을 참조하세요.