UWSGI

uWSGI는 파이썬 웹 애플리케이션을 위한 강력하고 유연한 애플리케이션 서버이다.
WSGI(Web Server Gateway Interface) 프로토콜을 구현하여 웹 서버와 파이썬 웹 애플리케이션 간의 표준화된 인터페이스를 제공한다.

적절한 설정과 튜닝을 통해 고성능, 안정성, 확장성을 제공하여 프로덕션 환경에서 파이썬 웹 애플리케이션을 효과적으로 운영할 수 있게 해준다.

uWSGI의 주요 특징

  1. 다양한 프로토콜 지원: HTTP, FastCGI, SCGI 등 여러 프로토콜을 지원한다.
  2. 고성능: 멀티 프로세싱과 멀티스레딩을 지원하여 높은 동시성과 성능을 제공한다.
  3. 유연성: 다양한 설정 옵션을 통해 세밀한 성능 튜닝이 가능한다.
  4. 플러그인 아키텍처: C, C++, Python 등 다양한 언어로 플러그인을 개발할 수 있어 확장성이 뛰어나다.
  5. 프로세스 관리: 마스터 프로세스가 워커 프로세스를 효율적으로 관리한다.

uWSGI의 장점

  1. 높은 성능: 효율적인 리소스 관리로 높은 처리량을 제공한다.
  2. 안정성: 마스터 프로세스가 워커 프로세스를 관리하여 안정적인 운영이 가능하다.
  3. 유연성: 다양한 설정 옵션으로 다양한 환경에 적응할 수 있다.
  4. 확장성: 플러그인 아키텍처를 통해 기능을 확장할 수 있다.

uWSGI의 작동 방식

  1. 웹 서버(예: Nginx)가 클라이언트로부터 요청을 받는다.
  2. 웹 서버는 이 요청을 uWSGI 서버로 전달한다.
  3. uWSGI는 요청을 파이썬 애플리케이션(예: Django, Flask)에 전달한다.
  4. 파이썬 애플리케이션이 요청을 처리하고 응답을 생성한다.
  5. uWSGI는 이 응답을 웹 서버로 반환하고, 웹 서버는 최종적으로 클라이언트에게 응답을 전송한다.

uWSGI의 로드밸런싱

uWSGI는 내장된 로드 밸런싱 기능을 제공하여 여러 워커 프로세스 간에 요청을 효율적으로 분산시킬 수 있다.

uWSGI의 로드 밸런싱은 다음과 같이 작동한다:

  1. 마스터 프로세스와 워커 프로세스
    uWSGI는 마스터 프로세스를 생성하고, 이 마스터 프로세스가 여러 워커 프로세스를 fork한다.
    각 워커 프로세스는 독립적인 Python 인터프리터 인스턴스를 가지며, 자체 GIL(Global Interpreter Lock)을 갖는다.
  2. 요청 분배
    1. 마스터 프로세스가 들어오는 HTTP 요청을 받는다다.
    2. 마스터 프로세스는 사전 정의된 로드 밸런싱 알고리즘에 따라 요청을 워커 프로세스 중 하나에 할당한다.
    3. 선택된 워커 프로세스가 요청을 처리하고 응답을 반환한다.
  3. 로드 밸런싱 알고리즘
    uWSGI는 다양한 로드 밸런싱 알고리즘을 지원한다다:
    • Round Robin: 요청을 순차적으로 각 워커에 분배한다.
    • Least Connections: 현재 가장 적은 연결을 처리 중인 워커에 새 요청을 할당한다.
    • IP Hash: 클라이언트 IP 주소를 기반으로 요청을 특정 워커에 할당한다.
  4. 동적 스케일링
    uWSGI의 ‘cheaper’ 서브시스템을 사용하면 트래픽 변화에 따라 워커 프로세스 수를 동적으로 조절할 수 있다.
    이를 통해 리소스 사용을 최적화하고 예상치 못한 트래픽 급증에 대비할 수 있다.
  5. 장애 대응
    uWSGI는 워커 프로세스의 상태를 모니터링하고, 특정 워커가 응답하지 않거나 문제가 발생하면 해당 워커를 재시작하거나 트래픽을 다른 워커로 리다이렉트한다.

uWSGI의 로드 밸런싱 기능은 단일 서버 내에서 효과적으로 작동하며, 복잡한 설정 없이도 애플리케이션의 성능과 안정성을 향상시킬 수 있다.
그러나 대규모 분산 환경에서는 Nginx와 같은 전용 로드 밸런서와 함께 사용하는 것이 일반적이다.

uWSGI의 로드 밸런싱 기능을 설정하기 위해서는:

  1. 마스터 프로세스 활성화
  2. 워커 프로세스 설정
  3. 로드 밸런싱 알고리즘 선택
  4. 동적 스케일링 설정
  5. 소켓 설정
    등을 통해 여러 워커 프로세스간에 요청을 효과적으로 분산시킬 수 있다.

uWSGI의 로드 밸런싱 기능을 사용할 때는:

  1. 워커 프로세스 수 설정:
    단순히 CPU 코어 수의 2배로 설정하는 것은 충분하지 않다.
    애플리케이션과 시스템 특성에 맞게 실험을 통해 최적의 워커 수를 찾아야 한다.
  2. 메모리 사용량 모니터링:
    memory-report 옵션을 사용하여 메모리 사용량을 지속적으로 확인해야 한다.
  3. 버퍼 크기 조정:
    기본 버퍼 크기(4096바이트)가 부족할 경우 “invalid request block size” 오류가 발생할 수 있으므로 buffer-size 옵션으로 조정이 필요한다.
  4. 동적 스케일링 설정:
    cheaper 서브시스템을 활용하여 트래픽 변화에 따라 워커 수를 자동으로 조절할 수 있다.
  5. 커널의 로드 밸런싱 활용:
    특별한 경우가 아니라면 커널의 기본 로드 밸런싱을 신뢰하는 것이 좋다.
    균등 분배가 필요하다면 CPU 어피니티 옵션을 고려해볼 수 있다.
  6. 프록시 타임아웃 설정:
    리로드 시간이 길어질 경우 프록시의 연결 타임아웃을 적절히 조정해야 한다.
  7. 워커 재활용:
    max-requests, max-worker-lifetime, reload-on-rss 등의 옵션을 사용하여 워커를 주기적으로 재시작함으로써 메모리 누수 등의 문제를 예방할 수 있다.
     이러한 요소들을 주의해야 하며, 이들을 고려하여 uWSGI의 로드 밸런싱을 구성하고, 지속적인 모니터링과 튜닝을 통해 최적의 성능을 얻을 수 있다.

uWSGI와 Nginx의 조합

uWSGI와 Nginx를 함께 사용하면 다음과 같은 주요 장점들이 있다:

  1. 성능 향상
    1. 정적 파일 처리: Nginx가 정적 파일을 더 효율적으로 처리하여 uWSGI의 부하를 줄인다.
    2. 고성능 처리: Nginx는 수천 개의 동시 연결을 처리할 수 있는 안정적인 웹 서버이다.
    3. 캐싱: Nginx는 동적 콘텐츠 캐싱을 구현하여 서버 부하를 줄일 수 있다.
  2. 보안 강화
    1. DDoS 방어: Nginx가 요청을 필터링하고 제한하여 uWSGI 서버를 보호한다.
    2. SSL 종료: Nginx가 SSL 연결을 처리하여 uWSGI의 부담을 줄인다.
  3. 유연성 및 확장성
    1. 로드 밸런싱: Nginx가 여러 uWSGI 인스턴스 간에 요청을 분산시킬 수 있다.
    2. 리버스 프록시: Nginx가 uWSGI 앞에서 리버스 프록시 역할을 수행한다.
  4. 추가 기능
    1. HTTP 기능: Nginx는 압축, ETag, 액세스 로깅 등 다양한 HTTP 기능을 제공한다.
    2. URL 라우팅: Nginx를 통해 복잡한 URL 라우팅을 구현할 수 있다.
      이러한 장점들로 인해 Nginx와 uWSGI를 함께 사용하면 더 안정적이고 확장 가능한 웹 애플리케이션 배포가 가능해진다.

uWSGI 환경 설정

uWSGI는 다양한 설정 옵션을 제공한다.

고려할 사항

uWSGI를 설정하는데 있어 서버 환경과 애플리케이션의 특성에 따라 적절히 조정되어야 한다.
특히 Django나 Flask 애플리케이션의 경우, 다음과 같은 점들을 고려해야 한다.

  1. Django 애플리케이션의 경우 static 파일 서빙:
1
2
static-map = /static=/path/to/static
static-expires = /* 7776000
  1. Flask 애플리케이션의 경우 WSGI 호출 규칙:
1
2
callable = app
wsgi-file = app.py
  1. 개발 환경과 프로덕션 환경의 구분:
1
2
3
4
5
6
7
8
# 개발 환경
python-autoreload = 1
py-auto-reload = 1

# 프로덕션 환경
disable-logging = true
master = true
vacuum = true
  1. 프로세스와 스레드 설정은 서버의 CPU 코어 수와 메모리를 고려하여 설정해야 한다. 일반적으로 CPU 코어 수에 맞춰 프로세스를 설정하는 것이 좋다.
    • 소켓 설정에서는 Nginx와 같은 웹서버와 연동할 때는 Unix 소켓을, 직접 HTTP 서비스를 제공할 때는 http 옵션을 사용한다.
    • 로드 밸런싱 설정은 트래픽 패턴에 따라 조정이 필요하다. cheaper 옵션으로 동적으로 워커 수를 조절할 수 있다.
    • 메모리 관련 설정은 서버의 전체 메모리를 고려하여 설정해야 한다. reload-on-rss로 메모리 누수를 방지할 수 있다.
    • 로깅 설정은 디버깅과 모니터링을 위해 중요하다. logto로 별도의 로그 파일을 지정하고, log-maxsize로 로그 파일 크기를 제한할 수 있다.

다양한 설정 옵션

기본 프로젝트 설정

프로젝트의 기본적인 실행 환경을 설정하는 옵션.
Django나 Flask 애플리케이션을 실행하기 위한 필수적인 설정들이 포함된다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[uwsgi]
# 프로젝트 기본 설정
chdir = /path/to/your/project           # 프로젝트 루트 디렉토리 설정
module = myproject.wsgi:application     # WSGI 애플리케이션 모듈 경로
pythonpath = /path/to/your/project      # Python 패키지 검색 경로 추가
env = DJANGO_SETTINGS_MODULE=myproject.settings  # 환경변수 설정

# 가상환경 설정
home = /path/to/virtualenv              # 가상환경 경로
virtualenv = /path/to/virtualenv        # 가상환경 경로 (home과 동일한 역할)

# 실행 권한 설정
uid = www-data                          # 실행 사용자
gid = www-data                          # 실행 그룹
프로세스 및 스레드 관리

서버의 동시성과 성능을 제어하는 핵심적인 설정.
CPU 자원을 효율적으로 활용하기 위한 다양한 옵션들을 제공한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 마스터 프로세스 설정
master = true                           # 마스터 프로세스 활성화
pidfile = /tmp/project-master.pid       # 마스터 프로세스 PID 파일 위치

# 워커 프로세스 설정
processes = 4                           # 생성할 워커 프로세스 수
enable-threads = true                   # 스레드 지원 활성화
threads = 2                             # 프로세스당 스레드 수
thread-stacksize = 512                  # 스레드 스택 크기 (KB)

# 프로세스 관리
max-requests = 5000                     # 워커당 최대 요청 처리 수
max-worker-lifetime = 3600              # 워커 프로세스 최대 수명 (초)
reload-on-rss = 2048                   # 메모리 사용량에 따른 리로드 (MB)
worker-reload-mercy = 60               # 워커 종료 대기 시간 (초)
네트워크 및 프로토콜 설정

네트워크 연결과 관련된 설정.
Nginx와의 연동이나 독립 실행 시의 통신 방식을 정의한다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 소켓 설정
socket = /tmp/uwsgi.sock               # Unix 소켓 파일 경로
chmod-socket = 666                      # 소켓 파일 권한
http = :8000                           # HTTP 포트 바인딩
http-keepalive = true                  # HTTP keepalive 지원
http-timeout = 65                      # HTTP 요청 타임아웃 (초)

# 버퍼 설정
buffer-size = 32768                    # 요청 버퍼 크기
post-buffering = 16384                 # POST 요청 버퍼 크기
socket-timeout = 30                    # 소켓 타임아웃 (초)
리소스 관리 및 제한

서버 리소스 사용을 제어하고 모니터링하기 위한 설정.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 메모리 제한
limit-as = 256                         # 프로세스당 메모리 제한 (MB)
reload-on-rss = 200                    # RSS 기반 리로드 임계값 (MB)
memory-report = true                   # 메모리 사용량 보고 활성화

# CPU 제한
harakiri = 30                          # 요청 처리 제한 시간 (초)
harakiri-verbose = true                # 상세한 harakiri 로그
cpu-affinity = 1                       # CPU 코어 할당

# 파일 설명자 제한
listen = 2048                          # 리스닝 큐 크기
max-fd = 51200                         # 최대 파일 설명자 수
로깅 및 디버깅

애플리케이션 모니터링과 문제 해결을 위한 로깅 설정.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 로그 파일 설정
logto = /var/log/uwsgi/%n.log         # 로그 파일 경로
log-maxsize = 20971520                 # 로그 파일 최대 크기 (bytes)
log-backupname = /var/log/uwsgi/%n.old.log  # 백업 로그 파일명

# 로그 레벨 설정
log-4xx = true                         # 4xx 에러 로깅
log-5xx = true                         # 5xx 에러 로깅
log-slow = true                        # 느린 요청 로깅
log-date = true                        # 타임스탬프 포함
자동 재시작 및 리로드

애플리케이션의 안정성과 지속성을 보장하기 위한 설정.

1
2
3
4
5
6
7
8
9
# 자동 재시작 설정
auto-procname = true                   # 프로세스 이름 자동 설정
touch-reload = /path/to/project/reload # 파일 변경 시 재시작
py-auto-reload = 1                     # Python 파일 변경 감지
reload-mercy = 8                       # 리로드 대기 시간 (초)

# 재시작 조건 설정
max-requests = 1000                    # 최대 요청 수 도달 시 재시작
max-worker-lifetime = 3600             # 워커 최대 수명 (초)
최적화

애플리케이션의 성능을 향상시키기 위한 고급 설정.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 캐시 설정
cache2 = name=mycache,items=100        # 캐시 설정
cache-blocksize = 64                   # 캐시 블록 크기
cache-store = /tmp/uwsgicache         # 캐시 저장 위치

# 스레드 풀 설정
cheaper = 2                            # 최소 프로세스 수
cheaper-algo = spare                   # 프로세스 스케일링 알고리즘
cheaper-step = 1                       # 스케일링 단계
cheaper-idle = 60                      # 스케일링을 축소하기 위해 필요한 유휴 시간

시스템 서비스 등록

Systemd 서비스 파일을 작성
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[Unit]
Description=uWSGI instance to serve myproject
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/project
Environment="PATH=/path/to/project/venv/bin"
ExecStart=/path/to/project/venv/bin/uwsgi --ini /path/to/project/uwsgi.ini
ExecReload=/bin/kill -HUP $MAINPID
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all
Restart=always
RestartSec=5
StandardError=syslog
StandardOutput=syslog

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

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

# 서비스 시작
sudo systemctl start uwsgi

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

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

참고 및 출처

Fetching Title#htpu