Uvicorn: 파이썬 ASGI 서버 라이브러리 완벽 가이드

  • 카카오톡 공유하기
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 링크 복사하기

웹 애플리케이션 개발에서 빠르고 효율적인 서버는 필수적입니다. 파이썬 생태계에서 Uvicorn은 ASGI(Asynchronous Server Gateway Interface) 서버로서 비동기 웹 애플리케이션을 위한 강력한 솔루션을 제공합니다. 이 글에서는 Uvicorn의 설치부터 사용법, ASGI 인터페이스와의 관계, 그리고 실제 MCP(Model Context Protocol) 서버 구축 사례까지 상세히 알아보겠습니다.

Uvicorn이란?

Uvicorn은 파이썬으로 작성된 초고속 ASGI 서버 구현체입니다. 비동기 프레임워크를 지원하도록 설계되었으며, uvloop와 httptools를 기반으로 하여 놀라운 성능을 제공합니다. Uvicorn이라는 이름은 ‘Unicorn Velociraptor’에서 유래되었으며, 이는 속도와 강력함을 상징합니다.

Uvicorn 설치 방법

Uvicorn은 pip를 통해 쉽게 설치할 수 있습니다. 기본 설치와 추가 의존성을 포함한 설치 방법은 다음과 같습니다:

1. 기본 설치

2. 표준 의존성 포함 설치 (권장)

표준 설치는 uvloop(리눅스에서 성능 향상), httptools(HTTP 파싱 성능 향상), websockets(WebSocket 지원) 등의 추가 의존성을 포함합니다.

Uvicorn 사용법

Uvicorn은 명령줄 인터페이스(CLI)와 프로그래밍 방식 두 가지로 사용할 수 있습니다.

1. 명령줄에서 실행

여기서 `main:app`은 main.py 파일의 app 객체를 의미합니다. 주요 옵션은 다음과 같습니다:

  • –host: 바인딩할 호스트 (기본값: 127.0.0.1)
  • –port: 사용할 포트 (기본값: 8000)
  • –reload: 코드 변경 시 자동 재시작 (개발 환경에서 유용)
  • –workers: 워커 프로세스 수
  • –log-level: 로그 레벨 설정 (critical, error, warning, info, debug)
상세 옵션

2. 프로그래밍 방식으로 실행

import uvicorn

if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )

간단한 ASGI 애플리케이션 예제

# main.py
async def app(scope, receive, send):
    assert scope['type'] == 'http'
    
    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [
            [b'content-type', b'text/plain'],
        ],
    })
    
    await send({
        'type': 'http.response.body',
        'body': b'Hello, World!',
    })

ASGI 인터페이스 이해하기

ASGI(Asynchronous Server Gateway Interface)는 WSGI(Web Server Gateway Interface)의 비동기 버전으로, 파이썬 웹 서버와 애플리케이션 간의 표준 인터페이스를 정의합니다.

ASGI의 주요 특징:

  • 비동기 처리 지원 (async/await)
  • WebSocket과 같은 장기 연결 지원
  • HTTP/2 및 기타 프로토콜 지원
  • 동시성 처리 향상

ASGI 애플리케이션은 다음 세 가지 매개변수를 받는 호출 가능한 객체입니다:

  • scope: 요청 정보를 담은 딕셔너리
  • receive: 이벤트를 수신하는 비동기 함수
  • send: 이벤트를 전송하는 비동기 함수

Uvicorn과 관련 프레임워크

Uvicorn은 다양한 ASGI 호환 프레임워크와 함께 사용할 수 있습니다:

1. FastAPI

FastAPI는 현대적이고 빠른 웹 프레임워크로, Uvicorn과 함께 사용할 때 최고의 성능을 발휘합니다.

# fastapi_example.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello World"}

# 실행: uvicorn fastapi_example:app --reload

2. Starlette

Starlette는 가볍고 유연한 ASGI 프레임워크로, FastAPI의 기반이 되는 라이브러리입니다.

# starlette_example.py
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

async def homepage(request):
    return JSONResponse({"message": "Hello World"})

routes = [
    Route("/", endpoint=homepage)
]

app = Starlette(routes=routes)

# 실행: uvicorn starlette_example:app --reload

3. Django

Django 3.0부터 ASGI를 지원하므로 Uvicorn으로 실행할 수 있습니다.

4. Quart

Flask와 유사한 API를 가진 비동기 웹 프레임워크입니다.

# quart_example.py
from quart import Quart

app = Quart(__name__)

@app.route("/")
async def hello():
    return {"hello": "world"}

# 실행: uvicorn quart_example:app --reload

MCP(Model Context Protocol) 서버 구축 사례

MCP 서버는 여러 채널(HTTP, WebSocket, 메시징 큐 등)을 통해 데이터를 처리하는 서버를 의미합니다. Uvicorn은 이러한 MCP 서버 구축에 이상적인 선택입니다.

실시간 데이터 처리 MCP 서버 예제

# mcp_server.py
from fastapi import FastAPI, WebSocket, BackgroundTasks
from fastapi.responses import JSONResponse
import asyncio
import aioredis
import json

app = FastAPI()

# 연결된 WebSocket 클라이언트 저장
connected_clients = []

# Redis 연결 설정
redis = None

@app.on_event("startup")
async def startup_event():
    global redis
    redis = await aioredis.create_redis_pool("redis://localhost")
    # 백그라운드 작업 시작
    asyncio.create_task(process_messages())

@app.on_event("shutdown")
async def shutdown_event():
    # Redis 연결 종료
    if redis is not None:
        redis.close()
        await redis.wait_closed()

# WebSocket 연결 처리
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    connected_clients.append(websocket)
    try:
        while True:
            # 클라이언트로부터 메시지 수신
            data = await websocket.receive_text()
            # 메시지 처리 및 Redis에 저장
            await redis.publish("messages", data)
    except Exception as e:
        print(f"WebSocket error: {e}")
    finally:
        connected_clients.remove(websocket)

# HTTP API 엔드포인트
@app.post("/api/message")
async def post_message(message: dict, background_tasks: BackgroundTasks):
    # 메시지를 Redis에 발행
    background_tasks.add_task(publish_message, json.dumps(message))
    return JSONResponse({"status": "Message sent"})

async def publish_message(message: str):
    await redis.publish("messages", message)

# Redis 구독 및 메시지 처리
async def process_messages():
    channel = (await redis.subscribe("messages"))[0]
    while await channel.wait_message():
        message = await channel.get()
        # 모든 WebSocket 클라이언트에 메시지 브로드캐스트
        for client in connected_clients:
            try:
                await client.send_text(message.decode())
            except Exception as e:
                print(f"Error sending to client: {e}")

# 실행: uvicorn mcp_server:app --host 0.0.0.0 --port 8000 --workers 4

이 예제는 다음과 같은 MCP 서버의 핵심 기능을 보여줍니다:

  • HTTP API를 통한 메시지 수신
  • WebSocket을 통한 실시간 양방향 통신
  • Redis를 사용한 메시지 큐 및 발행-구독 패턴
  • 비동기 백그라운드 작업 처리
  • 여러 클라이언트에 메시지 브로드캐스팅

Uvicorn의 성능 최적화 팁

실제 프로덕션 환경에서 Uvicorn의 성능을 최대화하기 위한 팁:

  • 워커 수 최적화: CPU 코어 수 * 2 + 1 공식을 시작점으로 사용
  • Gunicorn과 함께 사용: 프로세스 관리를 위해 Gunicorn의 워커 클래스로 Uvicorn 사용
  • uvloop 활성화: Linux 환경에서 성능 향상을 위해 uvloop 사용
  • 로그 레벨 조정: 프로덕션 환경에서는 warning 또는 error 레벨 사용
  • 프록시 서버 사용: Nginx나 Traefik과 같은 프록시 서버 뒤에서 Uvicorn 실행

Gunicorn과 함께 Uvicorn 사용하기

결론

Uvicorn은 현대적인 파이썬 웹 애플리케이션을 위한 강력하고 빠른 ASGI 서버입니다. FastAPI, Starlette와 같은 비동기 프레임워크와 함께 사용할 때 최고의 성능을 발휘하며, MCP 서버와 같은 복잡한 시스템 구축에도 이상적입니다. 비동기 프로그래밍의 장점을 최대한 활용하고 싶다면, Uvicorn은 필수적인 도구가 될 것입니다.

파이썬 비동기 웹서버에서 Uvicorn은 중요한 서버 도구입니다. 이 글이 여러분의 ASGI 서버 구축에 도움이 되길 바랍니다!


게시됨

카테고리

작성자

댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다