본문 바로가기
Server

Uvicorn 서버 1회차: Uvicorn이 무엇인지, “서버”와 “앱”의 역할 분리 이해하기

by 마틴블레이크 2025. 12. 22.
반응형

:contentReference[oaicite:0]{index=0}

Uvicorn 서버 1회차 : Uvicorn이 무엇인지, “서버”와 “앱”의 역할 분리 이해하기

한눈에 보는 요약

Uvicorn은 “파이썬 웹서버”라기보다, ASGI 표준을 구현한 비동기 서버(런타임)입니다. 파이썬 코드 바로 앞에서 HTTP·WebSocket 요청을 받아 애플리케이션으로 전달하는 역할을 합니다.

기존 Django·Flask가 사용하던 WSGI는 동기 방식이고, FastAPI·Starlette이 사용하는 ASGI는 비동기(Async)·이벤트 루프 기반입니다. 이 차이를 이해하면 왜 Uvicorn이 필요한지 자연스럽게 보입니다.

웹 애플리케이션을 만들 때는 “요청을 받는 계층(서버)”과 “업무 로직을 처리하는 계층(앱)”을 분리해서 생각해야 합니다. Uvicorn은 서버, FastAPI/Starlette는 앱이라고 보면 이해가 쉽습니다.

이번 글에서는 pip install uvicorn부터 시작해 가장 단순한 ASGI 앱(FastAPI) 실행까지 따라 하며, 마지막에 “Uvicorn이 하는 일 5줄 요약” 메모로 정리합니다.

목차


핵심 포인트

  • Uvicorn은 파이썬 웹 프레임워크가 아니라, ASGI 애플리케이션을 실행하는 서버(런타임)입니다.
  • WSGI는 동기(Sync) 요청 처리에 최적화된 옛 표준이고, ASGI는 비동기(Async)·이벤트 루프를 지원하는 최신 표준입니다.
  • FastAPI·Starlette는 “ASGI 앱”을 제공하고, Uvicorn은 이 앱을 네트워크와 연결해 실제 요청을 처리합니다.
  • “서버(Uvicorn)”는 소켓 열기, HTTP 파싱, 연결 관리에 집중하고, “앱(FastAPI)”은 URL 라우팅, 비즈니스 로직 처리에 집중합니다.
  • 간단한 예제만으로도 pip install uvicorn, uvicorn main:app --reload 구조를 이해하면 이후 배포·확장 학습이 한층 쉬워집니다.

상세 설명

1. Uvicorn과 ASGI 서버의 정체

많이들 “Uvicorn = 파이썬 웹서버”라고 부르지만, 좀 더 정확하게는 ASGI 서버라고 이해하는 것이 좋습니다. ASGI는 “Asynchronous Server Gateway Interface”의 약자로, 파이썬 비동기 웹 애플리케이션을 표준화된 방식으로 실행하기 위한 인터페이스입니다.

구조를 단순화하면 다음과 같습니다.

  • 클라이언트(브라우저, 앱) → HTTP/WebSocket 요청 전송
  • Uvicorn(ASGI 서버) → 포트(예: 8000)를 열고 요청을 받아 ASGI 형식으로 파싱
  • ASGI 앱(FastAPI, Starlette 등) → 받은 요청을 처리하고 응답을 생성
  • Uvicorn → 앱이 반환한 응답을 실제 HTTP 응답으로 변환해 클라이언트에 전달

즉, Uvicorn은 “네트워크 세계”와 “파이썬 앱 세계” 사이를 이어주는 런타임·게이트웨이 역할을 합니다. 우리가 작성하는 코드는 대부분 FastAPI/Starlette 쪽에 있고, Uvicorn은 이 코드를 안전하고 빠르게 실행해 주는 실행기라고 볼 수 있습니다.

2. 이벤트 루프와 비동기(Async)의 감각

ASGI가 중요한 이유는 비동기(Async) 처리를 자연스럽게 지원하기 때문입니다. 파이썬의 asyncio에서는 “이벤트 루프(event loop)”라는 것이 중심에 있습니다. 이벤트 루프는 하나의 큰 반복문처럼 동작하며, 각 요청이 기다려야 하는 시간(예: DB 쿼리 대기, 외부 API 호출 대기)을 효율적으로 관리합니다.

ASGI 프레임워크(FastAPI 등)에서 엔드포인트를 async def로 정의하고, I/O 작업에 await를 사용하면, 하나의 프로세스 안에서 여러 요청이 겹쳐서 진행될 수 있습니다. 이 덕분에 WebSocket, 긴 SSE 응답, 외부 서비스와의 대량 연동 같은 시나리오를 더 잘 처리할 수 있습니다.

Uvicorn은 이런 이벤트 루프를 초기화하고, 들어오는 요청마다 적절히 태스크를 스케줄링해 ASGI 앱에 넘겨주는 역할을 담당합니다.

3. ASGI가 필요한 이유

WSGI 환경에서도 충분히 많은 웹서비스를 만들 수 있지만, 다음과 같은 요구가 강해지면서 ASGI가 등장하게 되었습니다.

  • WebSocket 채팅, 실시간 알림, 스트리밍 응답 등 지속 연결이 필요한 기능
  • 수많은 외부 API·DB와 동시에 통신해야 하는 고부하 시스템
  • 동기 방식만으로는 리소스를 너무 많이 쓰게 되는 I/O 중심 서비스

ASGI는 이러한 요구를 반영한 표준이고, Uvicorn은 이 표준을 따르는 서버 구현체 중 하나입니다. Gunicorn+WSGI가 “옛 세대” 조합이라면, Uvicorn+ASGI는 비동기 시대의 “새로운 기본 조합”이라고 이해하면 좋습니다.

3. WSGI vs ASGI 비교

이제 전통적인 WSGI와 ASGI를 비교하면서, Uvicorn이 어디에 위치하는지 정리해 보겠습니다.

WSGI와 ASGI 비교 표

아래 표는 WSGI와 ASGI의 주요 차이를 개념 위주로 정리한 것입니다.

구분 WSGI ASGI
처리 방식 동기(Sync) 요청/응답 1회 처리에 초점 비동기(Async)·이벤트 루프 기반, 동시에 여러 작업 처리
지원 프로토콜 주로 HTTP 1.x HTTP, WebSocket 등 다양한 프로토콜 확장 가능
대표 프레임워크 Django(전통 모드), Flask 등 FastAPI, Starlette, Django(ASGI 모드) 등
대표 서버 구현 Gunicorn, uWSGI 등 Uvicorn, Hypercorn, Daphne 등
비동기 처리 제한적, 별도 우회가 필요 코어 수준에서 비동기 지원, async/await 자연스러운 사용
주요 사용처 전통적인 웹사이트, 관리자 페이지 등 API 서버, 실시간 서비스, 마이크로서비스 등

정리하자면, Uvicorn은 “ASGI 서버” 열에 위치하는 실행기이고, FastAPI·Starlette는 “ASGI 프레임워크/앱”에 해당합니다.

4. 서버와 앱의 역할 분리 이해

초보자 입장에서 가장 헷갈리는 부분은 “서버와 앱의 경계”입니다. 단순하게 다음과 같이 나누어 생각하면 좋습니다.

  • 서버(Uvicorn)
    • 포트 열기(예: 8000), TCP 연결 관리
    • HTTP 요청/응답 메시지 파싱 및 직렬화
    • 이벤트 루프 관리, 태스크 스케줄링
    • 프로세스/워커 관리(여러 개 띄우는 경우)
  • 앱(FastAPI/Starlette)
    • URL → 어떤 함수로 보낼지 라우팅
    • 요청 데이터 검증, 비즈니스 로직 처리
    • DB, 외부 API 호출
    • 응답 바디 및 상태코드 생성

실무에서는 이 분리가 매우 중요합니다. 예를 들어, 로컬 개발에서는 uvicorn main:app --reload 하나로 충분하지만, 운영 환경에서는 gunicorn -k uvicorn.workers.UvicornWorker처럼 “프로세스를 관리하는 계층”과 “ASGI 서버 계층”을 또 한 번 나누기도 합니다. 오늘은 1회차이므로, 일단 “Uvicorn = 서버, FastAPI = 앱” 정도만 정확히 구분해 두시면 충분합니다.


5. 실습: Uvicorn으로 첫 ASGI 앱 실행

이제 아주 간단한 FastAPI 앱을 Uvicorn으로 실행해 보겠습니다. 가상환경 사용 여부는 선택이지만, 실제 프로젝트라면 가상환경 안에서 진행하는 것을 권장합니다.

  1. 필수 패키지 설치터미널(또는 명령 프롬프트)을 열고 아래 명령을 실행합니다.uvicorn[standard]는 Uvicorn 자체와 권장 의존성들을 함께 설치하는 옵션이고, fastapi는 ASGI 앱을 작성하기 위한 프레임워크입니다.
  2. pip install "uvicorn[standard]" fastapi
  3. 프로젝트 파일 만들기원하는 폴더에서 main.py 파일을 하나 생성합니다. 이 안에 FastAPI 앱을 작성하고, Uvicorn이 이 앱을 실행하게 됩니다.
  4. 애플리케이션 코드 작성main.py 안에 간단한 “Hello World” ASGI 앱을 작성합니다. 전체 코드는 아래 코드 예시에서 다시 정리하겠습니다.
  5. Uvicorn으로 서버 실행다시 터미널로 돌아와 다음 명령을 실행합니다.main:app은 “main.py 파일 안의 app 객체”를 의미합니다. --reload 옵션은 코드가 변경될 때마다 서버를 자동으로 재시작해 주는 개발용 옵션입니다.
  6. uvicorn main:app --reload
  7. 브라우저에서 확인명령이 성공하면 기본적으로 http://127.0.0.1:8000 주소에서 서버가 동작합니다. 브라우저에 접속해 “Hello Uvicorn” 같은 응답이 보인다면, Uvicorn이 ASGI 앱을 잘 실행하고 있다는 뜻입니다.

6. 전체 코드 예시

앞에서 설명한 내용을 하나의 예제로 정리한 코드입니다. FastAPI를 사용해 가장 단순한 ASGI 앱을 만들고, Uvicorn으로 실행합니다.

# main.py
from fastapi import FastAPI

# ASGI 앱 객체 생성
app = FastAPI()


# 루트 경로("/")에 대한 라우트 정의
@app.get("/")
async def read_root():
    # 여기서 DB 호출, 외부 API 호출 등 비동기 작업을 자유롭게 사용할 수 있습니다.
    return {"message": "Hello Uvicorn, Hello ASGI"}


# 선택 사항: 파이썬 코드로 직접 Uvicorn 실행하기
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
    )

위 예제에서 핵심은 app = FastAPI()가 바로 ASGI 애플리케이션 객체라는 점입니다. Uvicorn은 main:app을 인자로 받아 이 객체를 실행합니다. 엔드포인트 함수인 read_rootasync def로 정의되어 있으며, Uvicorn이 관리하는 이벤트 루프 위에서 비동기적으로 실행됩니다.

# 터미널에서 직접 실행
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

이 명령을 통해 “서버(Uvicorn)”와 “앱(FastAPI app)”이 어떻게 연결되는지 명확히 체감할 수 있습니다. Uvicorn은 지정한 포트에서 요청을 받고, 그 요청을 ASGI 규격에 맞춰 app에 전달한 뒤, 응답을 다시 HTTP 응답으로 변환해 클라이언트로 돌려보냅니다.

7. Uvicorn이 하는 일 5줄 요약

  • HTTP·WebSocket 등 네트워크 요청을 받아 ASGI 형식으로 변환합니다.
  • FastAPI·Starlette 같은 ASGI 앱을 이벤트 루프 위에서 실행합니다.
  • 앱이 반환한 응답을 실제 HTTP 응답으로 직렬화해 클라이언트에 돌려줍니다.
  • 포트, 연결, 워커, 이벤트 루프 등 서버 자원을 효율적으로 관리합니다.
  • 개발 환경에서는 --reload 등 옵션을 통해 편리한 개발 경험을 제공하고, 운영 환경에서는 고성능 API 서버의 기반이 됩니다.

추가로 생각해볼 점

  • 운영 단계로 넘어갈 때는 Gunicorn 등과 조합해 다중 워커 구조를 설계하고, 헬스 체크, 로깅, 모니터링을 함께 고려하는 것이 좋습니다.
  • FastAPI의 async/await 패턴에 익숙해질수록 Uvicorn의 이벤트 루프 활용도가 높아지므로, 별도로 파이썬 비동기 프로그래밍을 연습해 두면 큰 도움이 됩니다.
  • 추후에는 HTTPS(SSL), 리버스 프록시(Nginx), 컨테이너(Docker)와의 조합까지 확장하면 실무에 바로 투입 가능한 아키텍처를 설계할 수 있습니다.

 

반응형