이 가이드에서는 Python 프로그래밍 언어로 작성된 Cloud Run 서비스 최적화와 일부 최적화와 관련된 절충안을 파악하는 데 유용한 배경 정보를 설명합니다. 이 페이지의 정보는 Python에도 적용되는 일반 최적화 팁을 보완합니다.
이러한 기존 Python 웹 기반 애플리케이션의 권장사항과 최적화는 대부분 다음을 기반으로 합니다.
- 동시 요청 처리(스레드 기반 및 비차단 I/O 모두)
- 연결 풀링 및 중요하지 않은 함수 일괄 처리(예: 백그라운드 태스크로 trace 및 측정항목 전송)를 사용하여 응답 지연 시간 단축
컨테이너 이미지 최적화
컨테이너 이미지를 최적화하면 로드 시간과 시작 시간을 줄일 수 있습니다. 다음과 같은 방법으로 이미지를 최적화할 수 있습니다.
- 런타임에 앱에서 필요한 항목만 컨테이너에 넣기
- WSGI 서버 최적화
런타임에 앱에서 필요한 항목만 컨테이너에 넣기
컨테이너에 포함된 구성요소와 구성요소가 서비스 실행에 필요한지 여부를 고려합니다. 컨테이너 이미지를 최소화하는 방법에는 여러 가지가 있습니다.
- 더 작은 기본 이미지 사용
- 대용량 파일을 컨테이너 외부로 이동
더 작은 기본 이미지 사용
Docker Hub는 컨테이너 내 소스에서 Python을 설치하지 않기로 선택한 경우 사용할 수 있는 공식 Python 기본 이미지를 여러 개 제공합니다. Debian 운영체제를 기반으로 합니다.
Docker Hub의 python
이미지를 사용하는 경우 slim
버전을 사용하는 것이 좋습니다.
이러한 이미지는 예를 들어 애플리케이션에 수행할 필요가 없는 휠을 빌드하는 데 사용되는 많은 패키지와 함께 제공되지 않으므로 크기가 작습니다. 예를 들어 Python 이미지는 GNU C 컴파일러, 전처리기, 코어 유틸리티와 함께 제공됩니다.
기본 이미지에서 가장 큰 패키지 10개를 식별하려면 다음 명령어를 실행합니다.
DOCKER_IMAGE=python # or python:slim
docker run --rm ${DOCKER_IMAGE} dpkg-query -Wf '${Installed-Size}\t${Package}\t${Description}\n' | sort -n | tail -n10 | column -t -s $'\t'
이러한 하위 수준 패키지가 더 적기 때문에 slim
기반 이미지는 잠재적인 취약점에 대한 공격에 노출되는 영역이 더 적습니다. 이 이미지에는 소스에서 휠을 빌드하는 데 필요한 요소가 포함되어 있지 않을 수 있습니다.
Dockerfile에 RUN apt install
줄을 추가하여 특정 패키지를 다시 추가할 수 있습니다. Cloud Run에서 시스템 패키지를 사용하는 방법에 대해 자세히 알아보세요.
Debian 기반이 아닌 컨테이너에 대한 옵션도 있습니다. python:alpine
옵션을 사용하면 컨테이너가 크게 작아질 수 있지만 많은 Python 패키지에는 알파 기반 시스템을 지원하는 사전 컴파일된 휠이 없을 수 있습니다. 지원은 개선되지만(PEP-656 참조) 계속 다릅니다. 패키지 관리자, 셸 또는 기타 프로그램이 포함되지 않은 distroless base image
를 사용하는 것이 좋을 수도 있습니다.
대용량 파일을 컨테이너 외부로 이동
미디어 애셋 등과 같은 대용량 파일을 기본 컨테이너에 포함할 필요가 없습니다.
Google Cloud는 Cloud Storage와 같은 호스팅 옵션을 여러 개 제공하여 이러한 대용량 항목을 저장합니다. 대규모 애셋을 이러한 서비스로 이동한 후 런타임 시 애플리케이션에서 참조합니다.
WSGI 서버 최적화
Python은 WSGI 표준 PEP-3333을 구현하여 애플리케이션이 웹 서버와 상호작용하는 방법을 표준화했습니다. 보다 일반적인 WSGI 서버 중 하나는 gunicorn
이며 이는 많은 샘플 문서에서 사용됩니다.
gunicorn 최적화
gunicorn
호출을 최적화하려면 다음 CMD
를 Dockerfile
에 추가합니다.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
이러한 설정을 변경하려는 경우 애플리케이션별로 작업자와 스레드의 수를 조정합니다. 예를 들어 작업자를 사용 가능한 코어 수와 같은 수로 사용하여 성능이 향상되었는지 확인한 후 스레드 수를 조정해 봅니다. 작업자 또는 스레드를 너무 많이 설정하면 콜드 스타트 지연 시간 증가, 메모리 소비 증가, 초당 요청 수 감소와 같은 부정적인 영향이 발생할 수 있습니다.
기본적으로 gunicorn
은 애플리케이션 코드를 평가하기 전이더라도 시작 시 작업자를 생성하고 지정된 포트를 리슨합니다. 이 경우 Cloud Run 기본 시작 프로브가 $PORT
에서 리슨하는 즉시 컨테이너 인스턴스를 정상으로 표시하므로 서비스에 커스텀 시작 프로브를 설정해야 합니다.
이 동작을 변경하려면 --preload
설정을 사용해 gunicorn
을 호출하여 리슨 전에 애플리케이션 코드를 평가하면 됩니다. 이렇게 하면 다음과 같은 이점이 있습니다.
- 배포 시 심각한 런타임 버그 식별
- 메모리 리소스 저장
추가하기 전에 애플리케이션에서 미리 로드하는 항목을 고려해야 합니다.
기타 WSGI 서버
컨테이너에서 Python을 실행하는 데 gunicorn
을 사용하도록 제한되지는 않습니다.
컨테이너 런타임 계약에 따라 컨테이너가 HTTP 포트 $PORT
에서 리슨하는 한 모든 WSGI 또는 ASGI 웹 서버를 사용할 수 있습니다.
일반적인 대안으로는 uwsgi
, uvicorn
, waitress
가 있습니다.
예를 들어 app
객체가 포함된 main.py
라는 이름의 파일에서는 다음 호출로 WSGI 서버가 시작됩니다.
# uwsgi: pip install pyuwsgi
uwsgi --http :$PORT -s /tmp/app.sock --manage-script-name --mount /app=main:app
# uvicorn: pip install uvicorn
uvicorn --port $PORT --host 0.0.0.0 main:app
# waitress: pip install waitress
waitress-serve --port $PORT main:app
Dockerfile
에 CMD exec
줄로 추가하거나 Google Cloud 빌드팩을 사용할 때 Procfile
에 web:
항목으로 추가할 수 있습니다.
애플리케이션 최적화
Cloud Run 서비스 코드에서 시작 시간을 단축시키고 메모리 사용량을 향상시키도록 최적화할 수도 있습니다.
스레드 줄이기
차단하지 않는 반응형 전략을 사용하고 백그라운드 활동을 방지하여 스레드 수를 줄임으로써 메모리를 최적화할 수 있습니다. 또한 일반 팁 페이지에 설명되어 있듯이 파일 시스템에 기록하지 마세요.
Cloud Run 서비스에서 백그라운드 활동을 지원하려면 요청 외부에서 백그라운드 활동을 실행하고 CPU 액세스 권한을 유지할 수 있도록 Cloud Run 서비스 CPU를 항상 할당되도록 설정합니다.
시작 태스크 줄이기
Python 웹 기반 애플리케이션은 시작 시 여러 태스크(예: 데이터 사전 로드, 캐시 준비, 연결 풀 설정)을 완료해야 할 수 있습니다. 이러한 태스크를 순차적으로 실행하면 애플리케이션 속도가 느려질 수 있습니다. 반면, 이들 태스크를 동시에 실행하려면 CPU 코어 수를 늘려야 합니다.
Cloud Run은 현재 실제 사용자 요청을 보내서 콜드 스타트 인스턴스를 트리거합니다. 새로 시작된 인스턴스에 요청이 할당된 사용자는 긴 지연 시간을 경험할 수 있습니다. Cloud Run에는 현재 '준비' 확인 기능이 없으므로 준비되지 않은 애플리케이션에 요청을 보내지 않을 방법이 없습니다.
다음 단계
자세한 내용은 다음을 참조하세요.