Gunicorn

Gunicorn(Green Unicorn)은 Python WSGI(Web Server Gateway Interface) HTTP 서버로, 파이썬 웹 애플리케이션을 위한 강력하고 효율적인 서버 솔루션이다.

Gunicorn은 웹 서버(예: Nginx)와 파이썬 웹 애플리케이션(예: Django, Flask) 사이에서 중개자 역할을 한다.

주요 기능은 다음과 같다:

  1. 웹 서버로부터 받은 HTTP 요청을 파이썬 애플리케이션이 이해할 수 있는 형태로 변환
  2. 파이썬 애플리케이션의 응답을 웹 서버에 전달
  3. 다중 프로세스를 통한 요청 처리로 성능 향상

Gunicorn의 특징

  1. 멀티 프로세싱: Gunicorn은 여러 워커 프로세스를 생성하여 동시에 많은 요청을 처리할 수 있다.
  2. 다양한 웹 프레임워크 지원: Django, Flask 등 대부분의 파이썬 웹 프레임워크와 호환된다.
  3. 자동 프로세스 관리: 서버 부하에 따라 워커 프로세스를 자동으로 관리한다.
  4. 유연한 설정: 다양한 설정 옵션을 통해 성능을 최적화할 수 있다.

Gunicorn의 작동 방식

Gunicorn은 pre-fork 모델을 기반으로 작동한다:

  1. 마스터 프로세스: 워커 프로세스들을 관리하고 모니터링한다.
  2. 워커 프로세스: 실제로 클라이언트의 요청을 처리한다.
    마스터 프로세스는 설정에 따라 여러 개의 워커 프로세스를 생성하고, 각 워커는 독립적으로 요청을 처리한다.

Gunicorn 사용의 이점

  1. 성능: 멀티 프로세싱을 통해 Django의 runserver보다 높은 성능을 제공한다.
  2. 안정성: 프로덕션 환경에서의 사용에 적합하며, 보안과 안정성이 검증되었다.
  3. 확장성: 워커 수 조절을 통해 서버 리소스에 맞게 확장 가능하다.
  4. 유연성: 다양한 설정 옵션을 통해 애플리케이션의 요구사항에 맞게 조정 가능하다.

Gunicorn 설정 및 사용

Gunicorn을 설치하고 사용하는 기본적인 단계는 다음과 같다:

  1. 설치: pip install gunicorn

  2. 실행: gunicorn [옵션] [WSGI_APP]
    예: gunicorn --workers=2 myproject.wsgi:application

  3. 설정 파일 사용: gunicorn -c config.py myproject.wsgi:application

Nginx와의 연동

프로덕션 환경에서는 Gunicorn을 Nginx와 함께 사용하는 것이 일반적이다.
Nginx는 정적 파일 서빙, 로드 밸런싱, SSL 처리 등을 담당하고, Gunicorn은 동적 콘텐츠 처리를 담당한다.

Gunicorn 환경 설정

서버의 용도와 환경에 따라 적절히 조정되어야 한다.
특히 실제 운영 환경에서는 다음과 같은 점들을 고려하여 설정을 조정해야 한다:

  1. 서버의 하드웨어 리소스 (CPU, 메모리)
  2. 예상되는 트래픽 패턴과 부하
  3. 애플리케이션의 특성 (I/O 중심인지, CPU 중심인지)
  4. 보안 요구사항
  5. 모니터링과 로깅 요구사항
    각 설정은 서버의 성능과 안정성에 직접적인 영향을 미치므로, 철저한 테스트를 통해 최적의 값을 찾아야 한다.
    또한, 정기적인 모니터링과 성능 측정을 통해 설정을 지속적으로 개선해 나가는 것이 중요하다.

다양한 설정 옵션

서버 기본 설정

서버의 기본적인 동작을 제어하는 설정.
이러한 설정은 Gunicorn이 어떻게 요청을 받고 처리할지를 결정한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# config.py
# 서버가 어디서 요청을 받을지 정의합니다
bind = '0.0.0.0:8000'  # IP:포트 형식으로 바인딩
# 또는 Unix 소켓을 사용할 수 있습니다
# bind = 'unix:/tmp/gunicorn.sock'

# 데몬 모드 설정
daemon = False  # 백그라운드 실행 여부

# 파이썬 경로 설정
pythonpath = '/path/to/project'

# 작업 디렉토리 설정
chdir = '/path/to/workdir'
워커 프로세스 설정

워커 프로세스는 실제로 요청을 처리하는 프로세스.
이 설정들은 서버의 성능과 리소스 사용에 직접적인 영향을 미친다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 워커 프로세스 관련 설정
workers = 4  # CPU 코어 수 * 2 + 1이 권장됨
worker_class = 'sync'  # 워커 클래스 선택
# 가능한 옵션: sync, eventlet, gevent, tornado, gthread

# 워커당 스레드 수 (gthread 워커 사용시)
threads = 2

# 워커 프로세스 타임아웃 설정
timeout = 30  # 요청 처리 제한 시간(초)
graceful_timeout = 30  # 그레이스풀 종료 대기 시간
max_requests = 1000  # 워커 재시작 전 처리할 최대 요청 수
max_requests_jitter = 50  # 재시작 타이밍의 무작위성 추가
Worker Class

worker_class는 Gunicorn이 요청을 처리하는 방식을 결정하는 매우 중요한 설정이다.
각 worker_class는 서로 다른 특징과 장단점을 가지고 있어, 애플리케이션의 성격에 따라 적절한 선택이 필요하다.

  1. Sync Worker (기본 워커)
    sync 워커는 Gunicorn의 기본 워커 클래스이다.
    Python의 기본적인 동기 처리 방식을 사용한다.

    1
    2
    3
    
    # config.py
    worker_class = 'sync'
    workers = 4  # CPU 코어 수 * 2 + 1 권장
    

    sync 워커는 각 요청을 순차적으로 처리한다.
    한 워커가 하나의 요청을 처리하는 동안 다른 요청은 대기해야 한다.
    는 간단하고 안정적이지만, I/O 작업이 많은 경우 성능이 제한될 수 있다.
    CPU 중심적인 작업이나 간단한 애플리케이션에 적합하다.

  2. Gevent Worker
    gevent 워커는 비동기 I/O를 지원하는 강력한 워커이다.
    Python의 greenlet을 사용하여 동시성을 구현한다.

    1
    2
    3
    
    # config.py
    worker_class = 'gevent'
    worker_connections = 1000  # 워커당 최대 동시 연결 수
    

    gevent는 I/O 작업이 많은 애플리케이션에서 뛰어난 성능을 발휘한다.
    특히 다음과 같은 상황에서 유용하다:

    • 많은 동시 연결이 필요한 경우
    • 외부 API 호출이 많은 경우
    • WebSocket 연결을 처리해야 하는 경우
      gevent는 코드를 수정하지 않고도 기존의 동기식 코드를 비동기식으로 실행할 수 있게 해주는 몽키 패칭(monkey patching) 기능을 제공한다:
    1
    2
    
    from gevent import monkey
    monkey.patch_all()
    
  3. Eventlet Worker
    eventlet 워커는 gevent와 비슷한 방식으로 동작하지만, 다른 비동기 라이브러리를 사용한다.

    1
    2
    3
    
    # config.py
    worker_class = 'eventlet'
    worker_connections = 1000
    

    eventlet은 다음과 같은 특징을 가진다:

    • 가벼운 동시성 처리
    • 네트워크 프로토콜 지원이 풍부
    • DNS 조회 최적화
    • 안정적인 비동기 처리
  4. Tornado Worker
    tornado 워커는 Python의 Tornado 웹 프레임워크의 비동기 기능을 활용한다.

    1
    2
    3
    
    # config.py
    worker_class = 'tornado'
    workers = 4
    

    tornado 워커는 다음과 같은 경우에 적합하다:

    • 장시간 연결이 필요한 애플리케이션
    • 비동기 특성이 중요한 실시간 애플리케이션
    • Tornado 프레임워크를 사용하는 애플리케이션
  5. Gthread Worker
    gthread 워커는 Python의 스레딩을 사용하여 동시성을 구현한다.

    1
    2
    3
    4
    
    # config.py
    worker_class = 'gthread'
    workers = 4
    threads = 2  # 워커당 스레드 수
    

    gthread는 다음과 같은 상황에서 유용하다:

    • I/O 바운드 작업이 많지만 gevent나 eventlet을 사용할 수 없는 경우
    • 스레드 기반의 처리가 필요한 경우
    • GIL(Global Interpreter Lock)의 영향을 받지 않는 작업이 많은 경우
  6. UVicorn Worker
    최신 버전의 Gunicorn은 UVicorn 워커도 지원한다.
    ASGI 애플리케이션을 위한 고성능 워커.

    1
    2
    3
    
    # config.py
    worker_class = 'uvicorn.workers.UvicornWorker'
    workers = 4
    

    UVicorn 워커는 다음과 같은 특징을 가진다:

    • ASGI 프로토콜 지원
    • WebSocket 지원
    • HTTP/2 지원
    • uvloop를 사용한 높은 성능
로깅 설정

로깅은 서버 모니터링과 문제 해결에 필수적.
적절한 로깅 설정은 운영 환경에서 문제를 신속하게 발견하고 해결하는 데 도움을 준다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 로깅 관련 설정
accesslog = '/var/log/gunicorn/access.log'
errorlog = '/var/log/gunicorn/error.log'
loglevel = 'info'
# 가능한 로그 레벨: debug, info, warning, error, critical

# 로그 포맷 설정
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'

# 로그 핸들러 설정
logconfig = 'logging.conf'
프로세스 보안 설정

보안 관련 설정은 서버의 안전한 운영을 위해 중요하다.
특히 프로덕션 환경에서는 이러한 설정들을 신중하게 고려해야 한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 프로세스 실행 권한 설정
user = 'www-data'
group = 'www-data'

# 프로세스 권한 제한
umask = 0o777
mode = 'production'

# SSL 설정
keyfile = '/path/to/keyfile'
certfile = '/path/to/certfile'
ssl_version = 'TLSv1_2'
성능 튜닝 설정

서버의 성능을 최적화하기 위한 설정.
이러한 설정은 서버의 부하와 리소스 사용량에 따라 조정되어야 한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 연결 관련 설정
backlog = 2048  # 대기열 크기
keepalive = 2  # Keep-Alive 연결 지속 시간
max_requests = 1000  # 워커 재시작 전 최대 요청 수
max_requests_jitter = 50  # 재시작 타이밍 분산

# 버퍼 설정
limit_request_line = 4094  # HTTP 요청 라인 최대 크기
limit_request_fields = 100  # HTTP 요청 헤더 필드 최대 개수
limit_request_field_size = 8190  # 헤더 필드 최대 크기
후킹 및 이벤트 핸들러 설정

서버의 다양한 생명주기 이벤트에 대응하기 위한 설정.
이를 통해 서버의 시작, 종료, 요청 처리 등의 과정에 커스텀 로직을 추가할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def on_starting(server):
    """서버 시작 시 실행되는 함수"""
    pass

def on_reload(server):
    """서버 리로드 시 실행되는 함수"""
    pass

def when_ready(server):
    """서버가 요청을 받을 준비가 되었을 때 실행되는 함수"""
    pass

def pre_fork(server, worker):
    """워커 프로세스 fork 전에 실행되는 함수"""
    pass

def post_fork(server, worker):
    """워커 프로세스 fork 후에 실행되는 함수"""
    pass

def pre_exec(server):
    """새로운 마스터 프로세스 실행 전에 실행되는 함수"""
    pass
환경 및 디버깅 설정

개발 및 디버깅을 위한 설정.
이러한 설정은 개발 환경과 프로덕션 환경에서 다르게 적용되어야 한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 환경 설정
raw_env = [
    'DJANGO_SETTINGS_MODULE=myproject.settings',
    'DATABASE_URL=postgresql://user:pass@localhost/dbname'
]

# 디버깅 설정
reload = False  # 코드 변경 시 자동 리로드
reload_engine = 'auto'  # 리로드 감지 엔진
spew = False  # 심각한 디버깅을 위한 설정
check_config = False  # 설정 체크 후 종료

시스템 서비스 등록

Systemd 서비스 파일을 작성
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[Unit]
Description=Gunicorn daemon for Django application
After=network.target
# 데이터베이스나 다른 서비스에 의존성이 있다면 여기에 추가
# Requires=postgresql.service
# After=postgresql.service

[Service]
# 서비스를 실행할 사용자와 그룹 설정
User=www-data
Group=www-data

# 작업 디렉토리 설정
WorkingDirectory=/path/to/your/django/project

# 가상환경 활성화 및 Gunicorn 실행
Environment="PATH=/path/to/your/virtualenv/bin"
ExecStart=/path/to/your/virtualenv/bin/gunicorn \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          --access-logfile /var/log/gunicorn/access.log \
          --error-logfile /var/log/gunicorn/error.log \
          your_project.wsgi:application

# 프로세스 재시작 설정
Restart=always
RestartSec=5

# 보안 관련 설정
PrivateTmp=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
서비스 파일을 시스템에 등록하고 활성화하는 방법
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 서비스 파일 복사
sudo cp gunicorn.service /etc/systemd/system/

# systemd 데몬 리로드
sudo systemctl daemon-reload

# 서비스 시작
sudo systemctl start gunicorn

# 부팅 시 자동 시작 설정
sudo systemctl enable gunicorn

# 서비스 상태 확인
sudo systemctl status gunicorn

참고 및 출처

Gunicorn - Python WSGI HTTP Server for UNIX