Gunicorn#
Gunicorn(Green Unicorn)은 Python WSGI(Web Server Gateway Interface) HTTP 서버로, 파이썬 웹 애플리케이션을 위한 강력하고 효율적인 서버 솔루션이다.
Gunicorn은 웹 서버(예: Nginx)와 파이썬 웹 애플리케이션(예: Django, Flask) 사이에서 중개자 역할을 한다.
주요 기능은 다음과 같다:
- 웹 서버로부터 받은 HTTP 요청을 파이썬 애플리케이션이 이해할 수 있는 형태로 변환
- 파이썬 애플리케이션의 응답을 웹 서버에 전달
- 다중 프로세스를 통한 요청 처리로 성능 향상
Gunicorn의 특징#
- 멀티 프로세싱: Gunicorn은 여러 워커 프로세스를 생성하여 동시에 많은 요청을 처리할 수 있다.
- 다양한 웹 프레임워크 지원: Django, Flask 등 대부분의 파이썬 웹 프레임워크와 호환된다.
- 자동 프로세스 관리: 서버 부하에 따라 워커 프로세스를 자동으로 관리한다.
- 유연한 설정: 다양한 설정 옵션을 통해 성능을 최적화할 수 있다.
Gunicorn의 작동 방식#
Gunicorn은 pre-fork 모델을 기반으로 작동한다:
- 마스터 프로세스: 워커 프로세스들을 관리하고 모니터링한다.
- 워커 프로세스: 실제로 클라이언트의 요청을 처리한다.
마스터 프로세스는 설정에 따라 여러 개의 워커 프로세스를 생성하고, 각 워커는 독립적으로 요청을 처리한다.
Gunicorn 사용의 이점#
- 성능: 멀티 프로세싱을 통해 Django의 runserver보다 높은 성능을 제공한다.
- 안정성: 프로덕션 환경에서의 사용에 적합하며, 보안과 안정성이 검증되었다.
- 확장성: 워커 수 조절을 통해 서버 리소스에 맞게 확장 가능하다.
- 유연성: 다양한 설정 옵션을 통해 애플리케이션의 요구사항에 맞게 조정 가능하다.
Gunicorn 설정 및 사용#
Gunicorn을 설치하고 사용하는 기본적인 단계는 다음과 같다:
설치: pip install gunicorn
실행: gunicorn [옵션] [WSGI_APP]
예: gunicorn --workers=2 myproject.wsgi:application
설정 파일 사용: gunicorn -c config.py myproject.wsgi:application
Nginx와의 연동#
프로덕션 환경에서는 Gunicorn을 Nginx와 함께 사용하는 것이 일반적이다.
Nginx는 정적 파일 서빙, 로드 밸런싱, SSL 처리 등을 담당하고, Gunicorn은 동적 콘텐츠 처리를 담당한다.
Gunicorn 환경 설정#
서버의 용도와 환경에 따라 적절히 조정되어야 한다.
특히 실제 운영 환경에서는 다음과 같은 점들을 고려하여 설정을 조정해야 한다:
- 서버의 하드웨어 리소스 (CPU, 메모리)
- 예상되는 트래픽 패턴과 부하
- 애플리케이션의 특성 (I/O 중심인지, CPU 중심인지)
- 보안 요구사항
- 모니터링과 로깅 요구사항
각 설정은 서버의 성능과 안정성에 직접적인 영향을 미치므로, 철저한 테스트를 통해 최적의 값을 찾아야 한다.
또한, 정기적인 모니터링과 성능 측정을 통해 설정을 지속적으로 개선해 나가는 것이 중요하다.
다양한 설정 옵션#
서버 기본 설정#
서버의 기본적인 동작을 제어하는 설정.
이러한 설정은 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는 서로 다른 특징과 장단점을 가지고 있어, 애플리케이션의 성격에 따라 적절한 선택이 필요하다.
Sync Worker (기본 워커)
sync 워커는 Gunicorn의 기본 워커 클래스이다.
Python의 기본적인 동기 처리 방식을 사용한다.
1
2
3
| # config.py
worker_class = 'sync'
workers = 4 # CPU 코어 수 * 2 + 1 권장
|
sync 워커는 각 요청을 순차적으로 처리한다.
한 워커가 하나의 요청을 처리하는 동안 다른 요청은 대기해야 한다.
는 간단하고 안정적이지만, I/O 작업이 많은 경우 성능이 제한될 수 있다.
CPU 중심적인 작업이나 간단한 애플리케이션에 적합하다.
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()
|
Eventlet Worker
eventlet 워커는 gevent와 비슷한 방식으로 동작하지만, 다른 비동기 라이브러리를 사용한다.
1
2
3
| # config.py
worker_class = 'eventlet'
worker_connections = 1000
|
eventlet은 다음과 같은 특징을 가진다:
- 가벼운 동시성 처리
- 네트워크 프로토콜 지원이 풍부
- DNS 조회 최적화
- 안정적인 비동기 처리
Tornado Worker
tornado 워커는 Python의 Tornado 웹 프레임워크의 비동기 기능을 활용한다.
1
2
3
| # config.py
worker_class = 'tornado'
workers = 4
|
tornado 워커는 다음과 같은 경우에 적합하다:
- 장시간 연결이 필요한 애플리케이션
- 비동기 특성이 중요한 실시간 애플리케이션
- Tornado 프레임워크를 사용하는 애플리케이션
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)의 영향을 받지 않는 작업이 많은 경우
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