Uvicorn - Python ASGI 서버
TL;DR
- ⚠️ 프로덕션에서는 Nginx에서 SSL 처리를 권장 (Let’s Encrypt 등) Uvicorn, ASGI, WSGI, uvloop, httptools, Gunicorn, FastAPI, Starlette, Worker, 비동기, 이벤트 루프, Nginx, 리버스 프록시
- Uvicorn - Python ASGI 서버를 알아두면 설계 판단과 구현 선택을 더 분명하게 할 수 있다.
- 원문 전체는 아래 상세 내용에 그대로 포함했다.
1. 개념
⚠️ 프로덕션에서는 Nginx에서 SSL 처리를 권장 (Let’s Encrypt 등) Uvicorn, ASGI, WSGI, uvloop, httptools, Gunicorn, FastAPI, Starlette, Worker, 비동기, 이벤트 루프, Nginx, 리버스 프록시
2. 배경
Uvicorn, ASGI, WSGI, uvloop, httptools, Gunicorn, FastAPI, Starlette, Worker, 비동기, 이벤트 루프, Nginx, 리버스 프록시
3. 이유
Uvicorn - Python ASGI 서버를 알아두면 설계 판단과 구현 선택을 더 분명하게 할 수 있다.
4. 특징
Uvicorn - Python ASGI 서버의 특징, 장단점, 적용 포인트를 원문에서 자세히 확인할 수 있다.
5. 상세 내용
Uvicorn - Python ASGI 서버
1. Uvicorn이란?
┌─────────────────────────────────────────────────────────────┐
│ │
│ Uvicorn = 초고속 ASGI 웹 서버 │
│ │
│ 이름 유래: UV (Unicorn의 변형) + ASGI │
│ 탄생: 2017년 (Tom Christie 개발) │
│ 특징: 비동기, 빠름, 가벼움 │
│ │
│ 핵심 역할: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 인터넷 ───────► Uvicorn ───────► FastAPI/Starlette │ │
│ │ (HTTP 요청) (ASGI 서버) (Python 앱) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 비유: │
│ ├── FastAPI = 요리사 (요청을 처리하는 로직) │
│ └── Uvicorn = 식당 입구 (요청을 받아서 요리사에게 전달) │
│ │
└─────────────────────────────────────────────────────────────┘
2. WSGI vs ASGI 역사 (배경)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 2003년: WSGI (Web Server Gateway Interface) 탄생 │
│ ├── PEP 333 (Python 표준) │
│ ├── 동기(Synchronous) 방식 │
│ ├── 요청 하나 = 스레드 하나 │
│ └── 구현체: Gunicorn, uWSGI │
│ │
│ WSGI의 한계: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ def wsgi_app(environ, start_response): │ │
│ │ # 동기적으로만 실행 가능 │ │
│ │ # WebSocket? ❌ 불가능 │ │
│ │ # async/await? ❌ 불가능 │ │
│ │ # HTTP/2? ❌ 제한적 │ │
│ │ return [b"Hello World"] │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 2016년: ASGI (Asynchronous Server Gateway Interface) 탄생 │
│ ├── Django Channels 프로젝트에서 시작 │
│ ├── 비동기(Asynchronous) 방식 │
│ ├── WebSocket, HTTP/2 지원 │
│ └── async/await 네이티브 지원 │
│ │
│ ASGI의 장점: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ async def asgi_app(scope, receive, send): │ │
│ │ # 비동기적으로 실행 가능 │ │
│ │ # WebSocket? ✓ 가능 │ │
│ │ # async/await? ✓ 네이티브 │ │
│ │ # HTTP/2? ✓ 가능 │ │
│ │ await send({"type": "http.response.body", ...})│ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2017년: Uvicorn 등장 │
│ ├── 최초의 순수 Python ASGI 서버 │
│ ├── uvloop 기반 (libuv 바인딩) │
│ └── FastAPI, Starlette와 함께 성장 │
│ │
└─────────────────────────────────────────────────────────────┘
3. 왜 Uvicorn인가?
┌─────────────────────────────────────────────────────────────┐
│ │
│ ASGI 서버 비교: │
│ │
│ ┌────────────┬─────────────────────────────────────────┐ │
│ │ 서버 │ 특징 │ │
│ ├────────────┼─────────────────────────────────────────┤ │
│ │ Uvicorn │ 가볍고 빠름, 개발용 기본 선택 │ │
│ │ │ uvloop 사용 시 매우 빠름 │ │
│ ├────────────┼─────────────────────────────────────────┤ │
│ │ Hypercorn │ HTTP/2, HTTP/3(QUIC) 지원 │ │
│ │ │ 더 많은 프로토콜 지원 │ │
│ ├────────────┼─────────────────────────────────────────┤ │
│ │ Daphne │ Django Channels 공식 서버 │ │
│ │ │ Django 프로젝트에서 주로 사용 │ │
│ └────────────┴─────────────────────────────────────────┘ │
│ │
│ Uvicorn이 인기 있는 이유: │
│ ├── FastAPI 공식 권장 서버 │
│ ├── 설정이 간단 │
│ ├── 성능이 뛰어남 (uvloop 사용 시) │
│ └── 활발한 개발/유지보수 │
│ │
└─────────────────────────────────────────────────────────────┘
4. 기본 사용법
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
# 실행 방법 1: CLI
# uvicorn main:app --reload
# 실행 방법 2: 코드에서 직접
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
# CLI 옵션들
uvicorn main:app \
--host 0.0.0.0 \ # 바인딩 주소 (기본: 127.0.0.1)
--port 8000 \ # 포트 (기본: 8000)
--reload \ # 코드 변경 시 자동 재시작 (개발용)
--workers 4 \ # 워커 프로세스 수 (프로덕션)
--loop uvloop \ # 이벤트 루프 (uvloop이 더 빠름)
--http httptools \ # HTTP 파서 (httptools이 더 빠름)
--log-level info # 로그 레벨
5. 아키텍처
┌─────────────────────────────────────────────────────────────┐
│ │
│ Uvicorn 아키텍처 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Internet │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Uvicorn Server │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ Event Loop (uvloop) │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌───────────┐ ┌───────────┐ │ │ │ │
│ │ │ │ │ HTTP │ │ WebSocket │ │ │ │ │
│ │ │ │ │ Protocol │ │ Protocol │ │ │ │ │
│ │ │ │ └─────┬─────┘ └─────┬─────┘ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ └──────┬───────┘ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ ▼ │ │ │ │
│ │ │ │ ┌─────────────────────────────┐ │ │ │ │
│ │ │ │ │ ASGI Interface │ │ │ │ │
│ │ │ │ │ scope, receive, send │ │ │ │ │
│ │ │ │ └──────────────┬──────────────┘ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ └─────────────────┼──────────────────┘ │ │ │
│ │ │ │ │ │ │
│ │ └────────────────────┼──────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ ASGI Application │ │ │
│ │ │ (FastAPI, Starlette, Django Channels) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ 핵심 컴포넌트: │
│ ├── uvloop: libuv 기반 초고속 이벤트 루프 │
│ ├── httptools: 초고속 HTTP 파서 (Node.js에서 사용) │
│ └── ASGI Interface: 앱과 서버 간의 표준 인터페이스 │
│ │
└─────────────────────────────────────────────────────────────┘
6. uvloop과 httptools
┌─────────────────────────────────────────────────────────────┐
│ │
│ uvloop (선택적, 권장): │
│ │
│ - libuv 기반 이벤트 루프 (Node.js가 사용하는 것) │
│ - 기본 asyncio 대비 2~4배 빠름 │
│ - Cython으로 작성되어 C 수준 성능 │
│ │
│ 설치: pip install uvloop │
│ 사용: uvicorn main:app --loop uvloop │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ httptools (선택적, 권장): │
│ │
│ - Node.js의 HTTP 파서를 Python으로 포팅 │
│ - 기본 파서 대비 훨씬 빠름 │
│ - Cython 기반 │
│ │
│ 설치: pip install httptools │
│ 사용: uvicorn main:app --http httptools │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 권장 설치 (둘 다 포함): │
│ │
│ pip install uvicorn[standard] │
│ │
│ 포함되는 것: │
│ ├── uvloop (Linux/macOS) │
│ ├── httptools │
│ ├── watchfiles (--reload용) │
│ └── websockets (WebSocket용) │
│ │
└─────────────────────────────────────────────────────────────┘
7. 개발 vs 프로덕션 설정
┌─────────────────────────────────────────────────────────────┐
│ │
│ 개발 환경: │
│ │
│ uvicorn main:app --reload │
│ │
│ ├── --reload: 코드 변경 감지 및 자동 재시작 │
│ ├── 단일 워커 (디버깅 용이) │
│ └── localhost만 바인딩 (보안) │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 프로덕션 환경 (방법 1: Uvicorn 직접): │
│ │
│ uvicorn main:app \ │
│ --host 0.0.0.0 \ │
│ --port 8000 \ │
│ --workers 4 \ │
│ --loop uvloop \ │
│ --http httptools │
│ │
│ ⚠️ --workers 사용 시 --reload 사용 불가 │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 프로덕션 환경 (방법 2: Gunicorn + Uvicorn Workers): │
│ │
│ gunicorn main:app \ │
│ -w 4 \ │
│ -k uvicorn.workers.UvicornWorker \ │
│ --bind 0.0.0.0:8000 │
│ │
│ 장점: │
│ ├── Gunicorn의 프로세스 관리 기능 활용 │
│ ├── 워커 재시작, 그레이스풀 셧다운 │
│ └── 프로덕션 검증된 프로세스 매니저 │
│ │
└─────────────────────────────────────────────────────────────┘
8. Worker 개수 설정
┌─────────────────────────────────────────────────────────────┐
│ │
│ 워커 수 계산 공식: │
│ │
│ workers = (CPU 코어 수 × 2) + 1 │
│ │
│ 예시: │
│ ├── 4코어 서버: (4 × 2) + 1 = 9 워커 │
│ ├── 8코어 서버: (8 × 2) + 1 = 17 워커 │
│ └── 하지만 보통 4~8개로 시작하고 조정 │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 고려 사항: │
│ │
│ I/O 바운드 작업 (DB, API 호출 등): │
│ └── 워커 수 늘려도 효과 좋음 │
│ │
│ CPU 바운드 작업 (계산, 이미지 처리 등): │
│ └── 코어 수 = 워커 수가 적절 │
│ │
│ 메모리 제한: │
│ └── 워커당 ~100MB+ 사용, 총 메모리 고려 │
│ │
│ ⚠️ 비동기 앱에서는 워커가 적어도 동시 처리 많음 │
│ └── async/await가 I/O 대기 중 다른 요청 처리 │
│ │
└─────────────────────────────────────────────────────────────┘
9. Nginx와 함께 사용 (프로덕션)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 일반적인 프로덕션 아키텍처: │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Client │────►│ Nginx │────►│ Uvicorn/Gunicorn│ │
│ │ │ │ (Reverse │ │ + FastAPI │ │
│ │ │ │ Proxy) │ │ │ │
│ └──────────┘ └──────────┘ └──────────────────┘ │
│ │
│ Nginx 역할: │
│ ├── SSL/TLS 종료 (HTTPS 처리) │
│ ├── 정적 파일 서빙 │
│ ├── 로드 밸런싱 │
│ ├── 요청 버퍼링 │
│ └── DDoS 방어 │
│ │
└─────────────────────────────────────────────────────────────┘
Nginx 설정 예시
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 지원
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 정적 파일 (Nginx가 직접 서빙)
location /static {
alias /app/static;
}
}
10. Docker에서 사용
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
# 의존성 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 소스 복사
COPY . .
# uvicorn[standard] 설치 (uvloop, httptools 포함)
RUN pip install uvicorn[standard]
# 포트 노출
EXPOSE 8000
# 프로덕션 실행
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db/mydb
depends_on:
- db
# Gunicorn + Uvicorn Worker 사용 시
command: >
gunicorn main:app
-w 4
-k uvicorn.workers.UvicornWorker
--bind 0.0.0.0:8000
db:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
11. 성능 비교
┌─────────────────────────────────────────────────────────────┐
│ │
│ 벤치마크 (요청/초, 단순 JSON 응답): │
│ │
│ ┌─────────────────────────┬───────────────────────────┐ │
│ │ 서버 구성 │ 요청/초 (RPS) │ │
│ ├─────────────────────────┼───────────────────────────┤ │
│ │ Uvicorn (기본) │ ~30,000 │ │
│ │ Uvicorn (uvloop) │ ~50,000+ │ │
│ │ Gunicorn + WSGI │ ~10,000 │ │
│ │ Flask (dev server) │ ~1,000 │ │
│ └─────────────────────────┴───────────────────────────┘ │
│ │
│ ⚠️ 실제 성능은 앱 로직, DB, 네트워크 등에 따라 다름 │
│ │
│ Uvicorn이 빠른 이유: │
│ ├── uvloop: C로 작성된 이벤트 루프 │
│ ├── httptools: C로 작성된 HTTP 파서 │
│ ├── 비동기: I/O 대기 중 다른 요청 처리 │
│ └── 경량: 최소한의 오버헤드 │
│ │
└─────────────────────────────────────────────────────────────┘
12. 로깅 설정
import uvicorn
from uvicorn.config import LOGGING_CONFIG
# 기본 로깅 설정 커스터마이징
LOGGING_CONFIG["formatters"]["default"]["fmt"] = \
"%(asctime)s - %(levelname)s - %(message)s"
LOGGING_CONFIG["formatters"]["access"]["fmt"] = \
'%(asctime)s - %(client_addr)s - "%(request_line)s" %(status_code)s'
if __name__ == "__main__":
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8000,
log_level="info",
access_log=True, # 접근 로그 활성화
)
# CLI에서 로그 레벨 설정
uvicorn main:app --log-level debug # debug, info, warning, error, critical
uvicorn main:app --access-log # 접근 로그 활성화
uvicorn main:app --no-access-log # 접근 로그 비활성화
13. SSL/HTTPS 설정
# 개발용 자체 서명 인증서 생성
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Uvicorn에서 HTTPS 사용
uvicorn main:app \
--host 0.0.0.0 \
--port 443 \
--ssl-keyfile key.pem \
--ssl-certfile cert.pem
# 코드에서 SSL 설정
import uvicorn
if __name__ == "__main__":
uvicorn.run(
"main:app",
host="0.0.0.0",
port=443,
ssl_keyfile="key.pem",
ssl_certfile="cert.pem",
)
⚠️ 프로덕션에서는 Nginx에서 SSL 처리를 권장 (Let’s Encrypt 등)
14. 정리
┌─────────────────────────────────────────────────────────────┐
│ │
│ Uvicorn 핵심 요약: │
│ │
│ 1. ASGI 서버 = 비동기 Python 앱을 실행하는 서버 │
│ │
│ 2. FastAPI/Starlette의 공식 권장 서버 │
│ │
│ 3. 성능을 위해 uvicorn[standard] 설치 │
│ └── uvloop + httptools 포함 │
│ │
│ 4. 개발: uvicorn main:app --reload │
│ │
│ 5. 프로덕션: │
│ ├── Uvicorn: --workers N --loop uvloop │
│ └── 또는 Gunicorn + UvicornWorker │
│ │
│ 6. 앞단에 Nginx 두면 더 좋음 │
│ └── SSL, 정적 파일, 로드밸런싱 │
│ │
│ 7. 워커 수: (CPU × 2) + 1 또는 4~8개로 시작 │
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 비유: │
│ ├── WSGI (Gunicorn) = 단일 창구 은행 (한 명씩 처리) │
│ └── ASGI (Uvicorn) = 번호표 은행 (대기하며 다른 일 처리) │
│ │
└─────────────────────────────────────────────────────────────┘
관련 키워드
Uvicorn, ASGI, WSGI, uvloop, httptools, Gunicorn, FastAPI, Starlette, Worker, 비동기, 이벤트 루프, Nginx, 리버스 프록시