웹 서버-애플리케이션 연결 메커니즘 5가지 완벽 비교

CGI: 프로세스 기반의 원시적 통신 규약

CGI는 웹 서버와 외부 프로그램 간의 최초 표준화된 상호작용 규약이다. 클라이언트의 HTTP 요청이 도착할 때마다 웹 서버는 새로운 프로세스를 생성하고, 해당 프로세스의 환경변수와 표준입력(stdin)을 통해 요청 정보를 전달한다. 스크립트가 처리를 마치면 표준출력(stdout)으로 결과를 반환하고 프로세스는 즉시 소멸된다.

이 방식의 치명적 한계는 요청마다 fork() + exec() 오버헤드가 발생한다는 점이다. 수십 동시 접속만으로도 시스템 리소스가 고갈되므로 현대 웹 환경에서는 역사적 유물로 전락했다.

FastCGI: 프로세스 풀을 통한 지속적 연결

FastCGI는 CGI의 근본적 비효율을 해소하기 위해 프로세스 풀(Pool) 개념을 도입했다. 마스터 프로세스가 워커 프로세스들을 미리 생성해두고, 요청이 들어올 때마다 유휴 워커에 할당하는 방식이다.

# Nginx에서 FastCGI 연동 예시
location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

프로세스 재사용 외에도 TCP/Unix 소켓을 통한 원격 배포가 가능하며, PHP-FPM 등 다양한 언어 생태계에서 여전히 표준으로 사용된다.

WSGI: 파이썬 생태계의 표준 게이트웨이

WSGI는 네트워크 프로토콜이 아닌 파이썬 함수 시그니처 규약이다. application(environ, start_response)라는 단일 호출 가능 객체(Callable)를 정의함으로써 프레임워크와 서버 간의 결합도를 낮춘다.

# WSGI 규약을 직접 구현한 최소 애플리케이션
def simple_app(env, start_response):
    status = '200 OK'
    headers = [('Content-Type', 'text/html; charset=utf-8')]
    start_response(status, headers)
    
    path = env.get('PATH_INFO', '/')
    body = f"<h1>요청 경로: {path}</h1>"
    return [body.encode('utf-8')]

# 내장 서버로 직접 실행
from wsgiref.simple_server import make_server

httpd = make_server('localhost', 8080, simple_app)
httpd.serve_forever()

Django의 wsgi.py나 Flask의 app 객체 모두 이 규약을 따른다. 핵심은 서버가 프레임워크를 직접 임포트하여 호출한다는 점이며, 이로 인해 둘은 반드시 같은 프로세스 공간에 존재해야 한다.

uwsgi 프로토콜: 바이너리 레벨의 고속 통신

소문자 uwsgi는 uWSGI 프로젝트가 정의한 바이너리 전송 프로토콜이다. HTTP나 FastCGI 같은 텍스트 기반 프로토콜과 달리, 패킷 헤더와 바디를 바이너리 형태로 직렬화하여 파싱 오버헤드를 최소화한다.

특성HTTPFastCGIuwsgi
전송 형식텍스트바이너리바이너리
헤더 오버헤드중간최소화
메타데이터 전달제한적표준화확장 가능
파이썬 특화아님아님최적화

이 프로토콜은 엄밀히 WSGI와 무관하며, 단순히 Nginx와 uWSGI 간의 전송 계층 역할을 수행한다.

uWSGI 서버: 생산 환경의 통합 실행 엔진

대문자 uWSGI는 C로 작성된 고성능 애플리케이션 서버다. WSGI 규약 구현 외에도 다음 기능을 내장한다:

  • 마스터-워커 프로세스 아키텍처: --workers 4로 다중 프로세스 운용
  • 프리포크(preload): 애플리케이션 코드를 fork() 전에 메모리에 적재
  • 해론(Harakiri): 응답 지연 워커의 강제 종료 및 재생성
  • 요청 로드 밸런싱: --cheaper-algo busyness로 동적 스케일링
; uWSGI 구성 파일 예시 (app.ini)
[uwsgi]
module = myproject:create_app()
master = true
processes = 4
socket = /run/uwsgi/app.sock
chmod-socket = 666
vacuum = true
die-on-term = true

실제 운영 아키텍처의 데이터 흐름

현대 파이썬 웹 서비스의 전형적인 요청 처리 경로는 다음과 같다:

  1. 클라이언트가 https://api.example.com/users로 요청 전송
  2. Nginx가 TLS 종료 및 호스트 기반 라우팅 수행
  3. Nginx가 Unix 소켓을 통해 uwsgi 프로토콜로 패킷 전달
  4. uWSGI 서버가 WSGI environ 딕셔너리 구성 후 파이썬 애플리케이션 호출
  5. Flask/Django가 비즈니스 로직 처리 및 응답 반환
  6. 역순으로 응답이 전달되어 클라이언트에 도달

이 구조에서 Nginx는 정적 파일 서빙, SSL/TLS, rate limiting, 캐싱 등 엣지 기능을 담당하고, uWSGI는 파이썬 인터프리터의 다중화와 안정적 실행을 책임진다. 각 계층의 분리는 장애 격리와 독립적 스케일링을 가능하게 한다.

태그: CGI FastCGI WSGI uwsgi

7월 23일 03:19에 게시됨