

목 차
1. 정리하는 계기
2. WSGI란?
3. guicorn이란?
4. ASGI란?
5. uvicorn이란?

파이썬으로 데이터를 서빙하는 백엔드 서버를 구성해보고 싶다는 생각에 진행했던
최근 프로젝트인 '자세 교정 웹' 프로젝트에서 파이선 프레임워크를 FastAPI로 선택하면서
웹을 띄우는 과정에서 uvicorn이 사용되었는데, 이걸 좀 더 알아보고 정리하고자 포스팅합니다.

로컬에서 장고 서버를 구동하기 위해서는 python manager.py runserver 처럼 장고의 내장 서버를 구동하는 방식을 사용.
장고의 내장서버
- 장고의 내장 서버는 이번 장에서 설명할 웹 서버와 WSGI 서버의 기능을 모두 포함하고 있다. 다만 내장 서버는 기능이 단순하고 '대량 요청'이나 '동시 요청'을 효율적으로 처리하지 못하므로 운영 환경에는 적합하지 않다.

웹 브라우저(Web Browser)는 사용자가 인터넷상의 웹 페이지와 기타 콘텐츠에 접근하고, 상호 작용하며, 그 내용을 볼 수 있도록 하는 소프트웨어 애플리케이션.
정적 페이지는 서버에 파일 형태로 저장되어 있으며, 사용자에게 요청될 때마다 동일한 내용을 제공하는 웹 페이지.
정의: 내용이 미리 완성되어 파일 시스템에 저장되어 있음.
사용자의 신원, 시간, 요청 내용과 관계없이 항상 똑같은 HTML, CSS, JavaScript 파일이 전송.
특징:
고정된 내용: 파일 내용 자체가 변하지 않습니다.
빠른 속도: 서버는 단순히 저장된 파일을 읽어 전송하기 때문에 처리 속도가 매우 빠릅니다.
낮은 부하: CPU 연산이나 데이터베이스(DB) 접근이 필요 없어 서버 부하가 낮습니다.
처리 주체: 주로 웹 서버 (예: Nginx, Apache)가 직접 처리.
WSGI와의 관계:
정적 파일 요청은 WSGI 서버로 전달되지 않고 웹 서버가 직접 처리하므로, WSGI는 관여하지 않음.

동적 페이지는 사용자의 요청 시점에 서버 측 프로그램(웹 애플리케이션)이 데이터베이스 조회나 비즈니스 로직을 수행하여 내용을 생성한 후 사용자에게 제공하는 웹 페이지.
정의: 요청마다 서버에서 데이터 처리 후 콘텐츠가 실시간으로 만들어지므로,
사용자나 시점에 따라 페이지 내용이 달라집니다.
특징:
가변적인 내용
: 요청 매개변수나 DB 상태에 따라 페이지 내용이 바뀜.
높은 유연성
: 사용자별 맞춤 정보, 검색 결과, 로그인 등 복잡한 기능을 구현할 수 있음.
상대적 부하
: DB 접근, 연산, 템플릿 렌더링 등의 과정이 필요하여 정적 페이지보다 처리 시간이 길고
서버 부하가 높음.
처리 주체: 웹 애플리케이션 서버(WAS) 또는 웹 프레임워크 (예: Django, Flask)가 담당.
WSGI와의 관계:
웹 서버가 동적 요청을 받으면, 이 요청을 파이썬 웹 애플리케이션으로 전달하기 위해
WSGI 표준을 따르는 WSGI 서버 (예: Gunicorn)를 중개자로 사용합니다. WSGI가 핵심적으로 작동하는 영역.

WSGI를 사용하는 일반적인 구성(Nginx/Apache + Gunicorn/uWSGI + Django/Flask)에서 요청은 다음과 같이 분리.
클라이언트 요청 수신: 웹 브라우저가 웹 서버(Nginx 등)에 요청을 보냅니다.
요청 종류 판단:
정적 요청 (.css, .js, .png 등): 웹 서버가 자신의 저장 공간에서 파일을 찾아 직접 클라이언트에 응답합니다.
동적 요청 (/login, /posts/123 등): 웹 서버는 요청을 WSGI 서버 (Gunicorn 등)로 전달(프록시)합니다.
동적 요청 처리: WSGI 서버는 WSGI 규약에 따라 요청을 파이썬 웹 애플리케이션으로 전달하고, 앱이 생성한 동적 콘텐츠를 받아 다시 웹 서버를 통해 클라이언트에게 응답합니다.

WSGI는 웹 서버(Web Server) 소프트웨어와 파이썬으로 작성된 웹 애플리케이션 또는 웹 프레임워크 간의 통신을 위한 표준 인터페이스(규약).
- 이 표준은 2003년 PEP 333으로 처음 제안되었고 이후 PEP 3333으로 개정되며 파이썬 웹 개발의 사실상 표준으로 자리 잡음.

정의.
주요 목적.
웹 서버와 어플리케이션 사이의 모든 상호작용에 대해 간단하고도 포괄적인 인터페이스를 제공하는 것.
- ex) 웹 서버로부터 HTTP 요청을 받은 경우 어플리케이션으로 전달할 때 어떤 형식(dict, str 혹은 bytes 등)으로 전달할지, 또 통신 중 예외 상황이 발생한 경우 어떻게 처리할지 등에 대한 명세를 담고 있음.
- 덕분에, Django,Flask를 사용하는 어플리케이션 개발자는 WSGI 내부 설계나 배포에 대한 고민 없이 어플리케이션 내부 프레임워크에만 집중 가능해짐.
필요성.

WSGI 아키텍처는 크게 3가지 핵심 컴포넌트로 구성.
역할:
예시:
역할:
예시:
역할:
예시:

WSGI는 본질적으로 서버와 애플리케이션 간의 호출 가능한 객체(Callable Object)를 통한 통신 규약.
WSGI 표준을 따르는 파이썬 애플리케이션은 반드시 다음 두 인수를 받는
'호출 가능한 객체'여야 함.
1. environ (환경 변수 딕셔너리):
2. start_response (콜백 함수):
1. 요청 수신
: 웹 서버(예: Nginx)가 클라이언트의 HTTP 요청을 수신.
2. WSGI 서버 호출
: 웹 서버는 요청을 WSGI 서버(예: Gunicorn)로 프록시(전달).
3. 애플리케이션 호출
: WSGI 서버는 HTTP 요청 정보를 파싱하여 environ 딕셔너리를 만들고,
자신의 콜백 함수인 start_response와 함께
WSGI 애플리케이션의 호출 가능한 객체를 실행.
# WSGI 애플리케이션의 기본 형태
def application(environ, start_response):
# 1. 응답 상태 및 헤더 설정
status = '200 OK'
headers = [('Content-type', 'text/plain')]
start_response(status, headers)
# 2. 응답 본문 반환 (반드시 이터러블한 바이트열(byte string)이어야 함)
return [b"Hello, WSGI World!"]
4. 응답 생성
: 애플리케이션은 environ을 기반으로 로직을 처리하고,
start_response를 호출하여 상태/헤더를 설정한 후,
응답 본문(바이트열의 이터러블 객체)을 반환.
5. 응답 전송.
: WSGI 서버는 start_response로 받은 상태/헤더와 애플리케이션이 반환한
응답 본문을 조합하여 완전한 HTTP 응답을 만든 후,
웹 서버를 통해 최종적으로 클라이언트에게 전송.


# main.py
def wsgi_app(environ, start_response):
status = "200 OK"
headers = [("Content-type", "text/plain")]
start_response(status, headers)
return [b"It Works!"]
어플리케이션은 반드시 callable 객체이어야 하며 다음 두 변수 environ, start_response를 입력받음.
- 다만, 어플리케이션 호출 시 위치 인자(positional arguments)로 입력받기 때문에
변수명을 동일하게 가질 필요는 없음.

start_response는 두 인자 status, response_headers와
선택적으로 exc_info를 입력받는 callable 객체.
호출 시 HTTP 응답 처리를 시작하며,
리턴값으로 write(body_data) callable 객체를 반환.




WSGI의 Guicorn은 파이썬 웹 환경을 배포할 때 가장 널리 사용되는 핵심 도구 중 하나.
정의
: Python WSGI HTTP 서버 (Python Web Server Gateway Interface HTTP Server)
역할
: 웹 서버(예: Nginx)와 파이썬 웹 애플리케이션(예: Django, Flask) 사이에서
WSGI 표준을 준수하며 요청을 처리하고 응답을 관리하는 게이트웨이 역할.
특징
: 구현이 심플하고, 서버 리소스 사용이 적으며, 비교적 빠른 속도로 동작하여 프로덕션(실제 서비스) 환경에 적합.
기반
: Ruby의 Unicorn 프로젝트에서 영감을 받아 이식된 Pre-fork(프리-포크) 워커 모델을 사용

(참고 : Django의 runserver 역시 똑같은 역할을 수행하지만 보안적으로나 성능적으로 검증이 되지 않았기 때문에 production 환경에서는 사용할 수 없다.) - 개발용으로는 유용

하지만 WSGI는 멀티 쓰레드를 만들 수 있기 때문에 Request가 많아지더라도 효율적으로 처리할 수 있음.
즉, production(제품) 환경에 적합

Gunicorn은 WSGI 아키텍처에서 WSGI 서버/게이트웨이 역할을 수행.
앞서 말했듯이, Django나 Flask의 내장 서버(runserver 등)는 개발 용도로만 적합하고 동시 요청 처리 및 보안에 취약.
Gunicorn은 멀티 프로세스/멀티 스레드 환경에서 동작하며 높은 동시성과 안정성을 제공하여 실제 서비스 환경(Production)에서 애플리케이션을 구동하는 데 사용.

Gunicorn은 'Master-Worker(마스터-워커)' 구조로 동작하여, 효율적으로 요청을 처리.
Gunicorn이 실행될 때 가장 먼저 생성되는 메인 프로세스.
'워커 프로세스'를 관리하고 모니터링하는 역할을 수행.
워커 프로세스가 비정상적으로 종료되면,
자동으로 새로운 워커를 생성하여 서버의 안정성을 유지.
마스터 프로세스가 복제(fork)하여 생성하는 실제 요청 처리 담당 프로세스
각 워커는 요청을 독립적으로 처리하며, 워커 수만큼 동시 요청을 처리 가능
Gunicorn은 기본적으로 '동기(Sync)'워커를 사용하지만,
'비동기(Async)워커'도 지원.
Gunicorn의 성능을 좌우하는 중요한 설정. 일반적으로 권장되는 워커 수는 다음과 같음.


Gunicorn은 명령 한 줄로 파이썬 애플리케이션을 WSGI 서버로 구동 가능.

최근 파이썬 웹 개발 환경에서는 WSGI의 후속으로 ASGI(Asynchronous Server Gateway Interface)가 등장.
ASGI (Asynchronous Server Gateway Interface)는 파이썬 웹 서버와 비동기(Asynchronous)를 지원하는 파이썬 웹 애플리케이션 및 프레임워크 간의 통신을 위한 표준 인터페이스이자 WSGI의 정신적 후계자.


WSGI는 웹소켓(WebSocket)이나 롱 폴링(Long Polling)과 같이 지속적 연결이나 비동기 통신이 필요한 현대적인 웹 환경을 효율적으로 처리하기 어렵기에 이를 해결하기 위해 등장.

비동기(Asynchronous) 방식을 지원
웹소켓, HTTP/2 등 비동기 및 동시성이 필요한 서비스에 적합
Uvicorn, Daphne, Hypercorn 등이 대표적인 ASGI 서버이며, FastAPI와 같은 최신 프레임워크가 이를 기반.

ASGI의 핵심은 파이썬의 async/await 기능을 웹 서버와 애플리케이션 간의 통신에 통합하여 높은 동시성과 새로운 웹 프로토콜을 지원하는 것.
기존의 WSGI는 요청-응답(Request-Response)의 단일 동기 호출 방식에 고정되어 있어서
다음과 같은 현대 웹 기술을 효율적으로 지원하기 어려웠음.
웹소켓(WebSocket)
: 클라이언트와 서버 간에 지속적인 양방향 통신 채널을 유지하는 프로토콜.
- (WSGI는 단발성 HTTP 요청에만 적합)
HTTP/2
: 하나의 연결로 여러 요청을 병렬 처리하는 동시성(Concurrency) 기능.
롱 폴링/서버 센트 이벤트(SSE)
: 서버가 클라이언트에게 실시간 데이터를 보내는 기술.

WSGI와 마찬가지로 ASGI도 서버와 애플리케이션 사이의 통신 규약을 정의하지만, 비동기 처리를 위해 인수의 구성이 다름.
ASGI 애플리케이션은 "호출 가능한 비동기 객체(Asynchronous Callable) 형태여야 하며,
3 가지 인수를 받음.




Uvicorn은 파이썬으로 작성된 '초고속 ASGI(Asynchronous Server Gateway Interface) 서버 구현체.
Uvicorn은 현대적인 비동기 파이썬 웹 서비스 환경에서 필수적인 역할을 수행하며, 특히 그 성능과 간결함으로 유명.
클라이언트의 HTTP 요청을 받아 ASGI 표준에 맞는 {scope, receive, send 구조}로
변환하여 애플리케이션에 전달 후,
반대로, 애플리케이션의 응답을 HTTP 응답 형태로 변환하여 클라이언트에게 전달.
Uvicorn의 놀라운 속도는 다음 두 가지 핵심 라이브러리를 활용하기 때문.

실제 프로덕션 환경에서는 Uvicorn을 단독으로 사용하기보다는 Gunicorn과 결합하여 사용하는 것이 일반적.

