o2o-infrakit/config/app-server/gunicorn_uvicorn.conf.py

257 lines
10 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
Gunicorn Configuration for Production FastAPI Service
=====================================================
환경: Production Level
서버 사양: 쿼드코어 CPU, 4GB RAM, ~50 req/s
백엔드: FastAPI REST API with Uvicorn Workers
프록시: Nginx (SSL/TLS, DDoS, Rate Limiting 처리)
=====================================================
"""
# ============================================================================
# 네트워크 바인딩 설정
# ============================================================================
# 바인딩 주소 및 포트
# 역할: Gunicorn이 수신할 네트워크 주소
# 0.0.0.0:8000 - 모든 네트워크 인터페이스에서 수신 (Docker/컨테이너 환경)
# 127.0.0.1:8000 - 로컬 전용 (Nginx와 동일 호스트, 보안 강화)
# Nginx 연동: Nginx가 외부 트래픽 처리, Gunicorn은 내부 전용
bind = "0.0.0.0:8000"
# ============================================================================
# Worker 프로세스 설정
# ============================================================================
# Worker 수
# 역할: 동시 요청 처리를 위한 프로세스 수
# 공식: I/O 집약적 작업 = (CPU 코어 * 2) + 1
# 계산: 쿼드코어(4) → 9개 권장, 하지만 4GB RAM 제약으로 4개 설정
# 각 워커 메모리: 200-500MB
# 4 워커 × 500MB = 2GB (시스템 예비 2GB 확보)
# 성능: ~50 req/s는 4개 워커로 충분 (워커당 ~12.5 req/s)
# 환경 변수: GUNICORN_WORKERS=6 으로 오버라이드 가능
# workers = multiprocessing.cpu_count() * 2 + 1
workers = 4
# Worker 클래스
# 역할: ASGI 애플리케이션(FastAPI) 처리를 위한 Worker 타입
# uvicorn.workers.UvicornWorker: 비동기 I/O, uvloop 이벤트 루프
# 기대 효과: sync 워커 대비 2-5배 높은 동시성, 메모리 효율적
worker_class = "uvicorn.workers.UvicornWorker"
# Worker 동시 연결 수 (주석 처리 - UvicornWorker는 이 설정 미사용)
# Nginx가 앞단에서 연결 관리하므로 불필요
# worker_connections = 1000
# ============================================================================
# 프로세스 관리 설정
# ============================================================================
# 데몬 모드
# 역할: 백그라운드 실행 여부
# False: systemd/Docker가 프로세스 관리 (현대적 방식)
# True: 수동 관리 시 사용 (pidfile 필수)
daemon = False
# PID 파일 (주석 처리 - systemd/Docker 사용 시 불필요)
# 역할: Master 프로세스 ID 저장
# 수동 관리 시 활성화: pidfile = '/var/run/gunicorn/gunicorn.pid'
# pidfile = '/tmp/gunicorn.pid'
# ============================================================================
# ASGI 애플리케이션 경로
# ============================================================================
# ASGI 애플리케이션 경로
# 역할: Gunicorn이 실행할 FastAPI 앱 지정
# 형식: "모듈경로:변수명"
# 예: config.asgi:application (Django 스타일)
# main:app (FastAPI 기본)
#wsgi_app = "main:app"
wsgi_app = "main:app"
# ============================================================================
# 타임아웃 설정
# ============================================================================
# Worker 타임아웃
# 역할: Worker가 요청 처리 최대 허용 시간 (초)
# 동작: 타임아웃 초과 시 Worker 강제 종료 후 재시작
# 계산: FastAPI REST API 평균 응답 1-5초
# 파일 업로드 고려 (100MB / 10Mbps = 80초)
# 비디오 생성, 이미지 처리 등 장기 실행 작업 고려
# Nginx 연동: proxy_read_timeout(300s)과 동일하게 설정
# 300초: 장기 실행 API (비디오 생성, 이미지 업로드 등) 지원
timeout = 300
# Keep-Alive 타임아웃
# 역할: HTTP Keep-Alive 연결 유지 시간 (초)
# 동작: 연결 재사용으로 핸드셰이크 오버헤드 감소
# Nginx 연동: Nginx keepalive_timeout(30s)보다 짧게 설정
# Nginx가 먼저 종료하도록 하여 리소스 효율화
# 2초: Nginx 앞단에서 연결 관리하므로 짧게 설정
keepalive = 2
# Graceful 종료 타임아웃
# 역할: Worker 재시작/종료 시 진행 중인 요청 완료 대기 시간 (초)
# 동작: SIGTERM 수신 후 새 요청 거부, 기존 요청 처리
# 타임아웃 초과 시 SIGKILL로 강제 종료
# 기대 효과: Graceful reload로 무중단 배포
# kill -HUP <pid> 또는 systemctl reload gunicorn
# timeout과 동일하게 설정
graceful_timeout = 300
# ============================================================================
# 프로세스 리소스 관리 (메모리 누수 방지)
# ============================================================================
# Worker 최대 요청 수
# 역할: Worker가 처리할 최대 요청 후 자동 재시작
# 목적: 메모리 누수 방어, 장기 운영 안정성
# 동작: max_requests 도달 시 Worker graceful 종료 후 재시작
# 계산: ~50 req/s 기준
# 1000으로 설정 시 워커당 20초마다 재시작 (1000/50)
# 메모리 누수 우려 시 유지, 안정적이면 5000-10000 증가 가능
# 모니터링: htop으로 워커 메모리 사용량 추이 확인
max_requests = 1000
# 최대 요청 수 Jitter
# 역할: max_requests에 랜덤성 추가
# 목적: 모든 Worker가 동시에 재시작하는 것 방지
# 동작: 실제 재시작 = max_requests ± random(0, jitter)
# 기대 효과: 재시작 부하 분산, 서비스 연속성 보장
# 권장: max_requests의 5-10%
max_requests_jitter = 50
# ============================================================================
# 애플리케이션 로딩 설정
# ============================================================================
# 애플리케이션 사전 로딩
# 역할: Worker fork 전 앱 로딩 방식 결정
# False: 각 Worker가 독립적으로 앱 로딩
# - 장점: Graceful reload 가능 (무중단 배포)
# - 단점: 메모리 중복 사용 (Worker 수만큼)
# True: Master 프로세스에서 앱 로딩 후 Worker fork
# - 장점: 메모리 20-40% 절감 (Copy-on-Write)
# - 단점: reload 시 전체 재시작 필요 (다운타임)
# 프로덕션 권장: False (무중단 배포 우선)
preload_app = False
# 코드 변경 감지 자동 재시작
# 역할: 파일 변경 시 Worker 자동 재시작
# 성능 영향: CPU 5-10% 오버헤드, 메모리 50-100MB 추가
# 보안: 예기치 않은 재시작으로 서비스 불안정
# **프로덕션에서는 반드시 False**
# 개발 환경에서만 True 사용
# 배포: CI/CD 파이프라인에서 명시적 재시작
reload = False
# ============================================================================
# 로깅 설정
# ============================================================================
# 애플리케이션 출력 캡처
# 역할: FastAPI의 print(), logging을 Gunicorn 로그로 리다이렉트
# False: 앱 로거가 독립적으로 관리 (권장)
# True: stdout/stderr를 errorlog로 통합
# FastAPI 권장: False (자체 로거 사용)
capture_output = False
# 로그 레벨
# 역할: 출력할 로그의 최소 수준
# 레벨: critical > error > warning > info > debug
# info: 일반 정보 + 에러 (프로덕션 권장)
# warning: 경고 이상만 (로그 양 감소)
# debug: 모든 세부 정보 (성능 저하, 개발용)
loglevel = "info"
# 액세스 로그 파일
# 역할: HTTP 요청 로그 저장
# 형식: 시간별 로그 파일 생성 (access_2025-01-05_14.log)
# 로테이션: 시간별 자동 분리, logrotate 추가 권장
# 성능: 버퍼링으로 I/O 최적화
# Docker/K8s: "-" 사용으로 stdout 출력 권장
accesslog = "/log/uvicorn/uvicorn_access.log"
# 에러 로그 파일
# 역할: Gunicorn 에러, Worker 크래시 로그
# 포함: Worker 타임아웃, 메모리 에러, 예외 등
# 모니터링: 장애 탐지를 위한 핵심 로그
errorlog = "/log/uvicorn/uvicorn_error.log"
# 액세스 로그 포맷 (선택사항, 필요 시 주석 해제)
# 역할: 요청 로그 형식 커스터마이징
# 기본 포맷으로도 충분, 상세 정보 필요 시 활성화
access_log_format = (
'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s %(p)s'
)
# 워커 프로세스 이름 설정 (모니터링 시 유용)
proc_name = "fastapi_gunicorn"
# ==========================================
# 성능 최적화
# ==========================================
# - 최대 2048개의 연결이 Accept Queue에서 대기 가능
# - 동시에 많은 연결 요청이 들어와도 2048개까지는 거부되지 않음
# - 실제 적용값 = min(2048, 시스템 somaxconn)
# 낮은 트래픽 (기본값 충분)
# backlog = 2048 # 기본값 사용
# workers = 4
#
# 높은 트래픽 (증가 필요)
# backlog = 4096
# workers = 8
# OS 설정도 함께 조정 필요
# /etc/sysctl.conf
# net.core.somaxconn = 4096
#
# 증가해야 할 때:
# ss -lnt 명령으로 Send-Q가 계속 가득 찬 경우
# ss -lnt | grep :8000
# 순간적인 트래픽 급증이 예상되는 경우
# connection refused 에러가 자주 발생하는 경우
backlog = 2048
# 임시 파일 디렉토리 (업로드 처리 시 사용)
# 재부팅 시 자동 삭제
# Gunicorn 기본값
# worker_tmp_dir = None # /tmp 디렉토리 사용 (디스크 기반)
# 사용하는 경우 (권장):
# 파일 업로드가 많은 서비스
# 큰 요청/응답 처리
# 충분한 RAM이 있는 경우
# RAM이 부족한 경우
# worker_tmp_dir = "/tmp" # 디스크 사용
# 파일 업로드/다운로드가 거의 없는 경우
# worker_tmp_dir = None # 기본값 사용
# Docker 사용시 고려 필요
# shm_size: '2gb' # /dev/shm 크기 증가
# volumes:
# - /dev/shm:/dev/shm # 호스트 공유 (선택)
# worker_tmp_dir = "/dev/shm" # RAM 기반 tmpfs 사용으로 I/O 성능 향상
worker_tmp_dir = None
"""
배포 전 체크리스트:
[권장]
1. 로그 로테이션 설정 (logrotate)
2. 헬스체크 엔드포인트 구현 (/health)
3. 성능 테스트 (wrk, locust)
성능 모니터링:
# 프로세스 확인
ps aux | grep gunicorn
# 리소스 사용량
htop -p $(pgrep -d',' gunicorn)
# 로그 실시간 확인
tail -f /log/uvicorn/access_*.log
tail -f /log/uvicorn/error_*.log
설정 최적화 가이드:
- workers: CPU 사용률 80% 이하 유지
- timeout: 응답 시간 + 여유분 (평균 * 2)
- max_requests: 메모리 누수 없으면 5000-10000으로 증가
- keepalive: Nginx keepalive_timeout보다 짧게
"""