ASGI를 활용한 파이썬 비동기 웹 잠재력 열기
Takashi Yamamoto
Infrastructure Engineer · Leapcell

소개
웹 개발 환경은 응답성, 확장성 및 효율성에 대한 요구가 증가함에 따라 끊임없이 진화하고 있습니다. 전통적인 동기식 파이썬 웹 프레임워크는 강력하고 널리 사용되었지만, 동시 I/O 바운드 작업을 처리할 때 종종 한계에 직면했습니다. 웹 서버가 다른 클라이언트 요청을 처리하기 전에 데이터베이스 쿼리가 완료되거나 외부 API 호출이 반환되기를 기다리는 상황을 상상해 보세요. 이러한 '차단' 동작은 결국 성능 병목 현상과 처리량 감소로 이어지며, 특히 부하가 많을 때 그렇습니다. 동기식 서버 측 코드의 본질적인 단일 스레드 특성은 파이썬에서 현대적이고 고성능의 웹 애플리케이션을 구축하는 데 상당한 장애물이 되고 있었습니다.
이것이 바로 ASGI, 즉 비동기 서버 게이트웨이 인터페이스가 등장하는 곳입니다. ASGI는 이러한 격차를 해소하기 위해 설계된 중요한 사양으로 등장했으며, 파이썬 웹 프레임워크가 비동기 서버와 상호 작용하는 방식을 근본적으로 변화시켰습니다. 비차단 I/O 및 비동기 프로그래밍 패러다임을 채택함으로써 ASGI는 파이썬 웹 개발에 새로운 시대를 열었으며, 개발자들이 수천 개의 동시 연결을 효율적으로 처리할 수 있는 고도의 동시적이고 확장 가능한 애플리케이션을 구축할 수 있도록 지원했습니다. 이 글에서는 ASGI의 복잡성을 깊이 파고들어 어떻게 작동하는지, 장점은 무엇인지, 비동기 파이썬 웹 서비스의 미래를 어떻게 형성하고 있는지 이해할 것입니다.
비동기 게이트웨이 이해하기
ASGI를 진정으로 높이 평가하려면 먼저 비동기 프로그래밍과 웹 서버 생태계에서 파이썬의 기반이 되는 몇 가지 핵심 개념을 파악해야 합니다.
주요 용어:
- 비동기 프로그래밍: 주 프로그램 스레드를 차단하지 않고 여러 작업을 동시에 수행할 수 있도록 하는 프로그래밍 패러다임입니다. 작업이 완료되기를 기다리는 대신, 프로그램이 다른 작업으로 전환했다가 준비가 되면 원래 작업을 재개할 수 있습니다. 파이썬에서는 주로
async
/await
구문과asyncio
라이브러리를 사용하여 구현됩니다. - 동기 프로그래밍: 작업이 순차적으로 실행되는 프로그래밍 패러다임입니다. 다음 작업을 시작하기 전에 각 작업이 완료되어야 하므로 '차단' 동작이 발생할 수 있습니다.
- 차단 I/O: 특정 입력/출력 작업(예: 디스크 읽기, 네트워크 요청)이 완료될 때까지 프로그램 실행이 중단되는 작업입니다.
- 비차단 I/O: I/O 작업이 완료되기를 기다리는 동안 프로그램이 다른 작업을 계속 실행할 수 있도록 하는 작업으로, 일반적으로 작업이 준비되었을 때 알림을 받습니다.
- WSGI (Web Server Gateway Interface): 파이썬 웹 서버와 웹 애플리케이션 프레임워크 간의 오래된 동기식 표준 인터페이스입니다. HTTP 요청을 처리하기 위한 간단한 호출 기반 인터페이스를 정의합니다.
- ASGI (Asynchronous Server Gateway Interface): 비동기 작업, WebSockets 및 장기 폴링을 파이썬 웹 애플리케이션에서 지원하도록 설계된 WSGI의 비동기 후속 사양입니다.
async
함수 콜러블을 중심으로 구축되었으며scope
,receive
,send
인수를 받습니다. - 웹 서버 (ASGI 서버): 들어오는 네트워크 요청(예: HTTP)을 수신하고 이를 해당 애플리케이션으로 라우팅하는 프로그램입니다. Uvicorn, Hypercorn, Daphne 등이 있습니다.
- ASGI 애플리케이션: ASGI 사양을 준수하는 파이썬 콜러블(
async
함수 또는__call__
메서드가 있는 클래스)입니다. 본질적으로 웹 프레임워크 또는 애플리케이션 코드입니다.
ASGI 작동 방식:
ASGI의 핵심은 비동기 파이썬 웹 서버(예: Uvicorn)와 비동기 웹 애플리케이션(예: FastAPI 또는 Starlette) 간의 보편적인 인터페이스 역할을 한다는 것입니다. WSGI의 단일 동기 callable(environ, start_response)
서명과 달리 ASGI는 세 가지 핵심 인수를 갖는 async
콜러블을 정의합니다.
async def application(scope, receive, send): # ... application logic ...
-
scope
: WSGI의environ
과 유사하지만 비동기 컨텍스트에 맞게 설계된 요청별 세부 정보가 포함된 사전입니다. HTTP 메서드, 경로, 헤더, 연결 세부 정보 및 이벤트 유형(예:'http'
,'websocket'
,'lifespan'
)과 같은 정보가 포함됩니다.- HTTP 요청의 경우
scope
에는type='http'
,method
,path
,headers
,query_string
등의 세부 정보가 포함됩니다. - WebSocket 연결의 경우
scope
에는type='websocket'
과 함께path
,headers
,subprotocols
등이 포함됩니다.
- HTTP 요청의 경우
-
receive
: 애플리케이션이 서버로부터 들어오는 메시지를 수신할 수 있도록 하는await
가능한 콜러블입니다. 이러한 메시지는 일반적으로 클라이언트 데이터, 연결 끊김 또는 수명 주기 이벤트와 같은 이벤트입니다. 수신된 각 메시지는 이벤트 유형과 해당 데이터가 포함된 사전입니다.- HTTP의 경우
receive
는 요청 본문 청크가 포함된'http.request'
메시지를 생성할 수 있습니다. - WebSocket의 경우
receive
는 클라이언트의 텍스트 또는 이진 데이터가 포함된'websocket.receive'
메시지를 생성할 수 있습니다.
- HTTP의 경우
-
send
: 애플리케이션이 서버로 메시지를 다시 보낼 수 있도록 하는await
가능한 콜러블이며, 서버는 이를 클라이언트로 전달합니다. 이러한 메시지는 응답, 데이터 또는 제어 신호를 나타냅니다.- HTTP의 경우
send
는'http.response.start'
(상태 코드, 헤더) 및'http.response.body'
(응답 본문 청크) 메시지를 보내는 데 사용됩니다. - WebSocket의 경우
send
는'websocket.send'
메시지(텍스트 또는 이진 데이터) 또는'websocket.close'
메시지를 보내는 데 사용됩니다.
- HTTP의 경우
간단한 ASGI 애플리케이션 예제 (최소 HTTP):
HTTP 요청에 응답하는 최소한의 ASGI 애플리케이션을 살펴보겠습니다.
async def homepage_application(scope, receive, send): if scope['type'] == 'http': # HTTP request handling await send({ 'type': 'http.response.start', 'status': 200, 'headers': [ [b'content-type', b'text/plain'], ], }) await send({ 'type': 'http.response.body', 'body': b'Hello, ASGI World!', }) elif scope['type'] == 'websocket': # WebSocket handling (simplified for demonstration) await send({ 'type': 'websocket.accept' }) while True: message = await receive() if message['type'] == 'websocket.receive': print(f"Received from WebSocket: {message['text']}") await send({ 'type': 'websocket.send', 'text': f"Echo: {message['text']}" }) elif message['type'] == 'websocket.disconnect': print("WebSocket disconnected") break
이를 실행하려면 Uvicorn과 같은 ASGI 서버가 필요합니다. 먼저 Uvicorn을 설치합니다: pip install uvicorn
. 그런 다음 터미널에서 실행할 수 있습니다.
uvicorn my_app:homepage_application --reload
(위 코드가 my_app.py
에 저장되어 있다고 가정). 이제 브라우저에서 http://127.0.0.1:8000/
를 방문하면 "Hello, ASGI World!"가 표시됩니다.
이 예제는 ASGI 서버와 애플리케이션 간의 기본 계약을 보여줍니다. 서버는 요청을 수신하고 scope
를 구성한 다음 receive
및 send
함수를 애플리케이션에 전달합니다. 그런 다음 애플리케이션은 send
를 사용하여 비동기적으로 요청을 처리하고 응답을 다시 보냅니다.
ASGI의 장점:
- 비동기 우선:
async
/await
를 직접 지원하여 ASGI 기반 프레임워크가 비차단 I/O를 활용할 수 있도록 합니다. - 프로토콜 비종속적: WSGI는 엄격하게 HTTP 기반인 반면, ASGI는 HTTP/1.1, HTTP/2, WebSockets 및 잠재적으로 더 많은 프로토콜을 포함한 다양한 프로토콜을 처리할 수 있어 매우 다재다능합니다.
- 고성능: 비차단 작업을 가능하게 함으로써 ASGI 기반 애플리케이션은 동기식 애플리케이션에 비해 훨씬 높은 동시성과 처리량을 달성할 수 있으며, 특히 I/O 바운드 작업의 경우 더욱 그렇습니다.
- 확장성: 적은 오버헤드로 많은 동시 연결을 처리하는 능력은 직접적으로 더 나은 확장성으로 이어집니다.
- 최신 웹 기능: WebSockets 및 서버 전송 이벤트(SSE)의 기본 지원은 실시간 상호작용 웹 애플리케이션을 구축하는 데 중요합니다.
- 생태계 성장: FastAPI, Starlette, Quart와 같은 새롭고 고성능의 비동기 프레임워크 생태계가 활발해졌으며, Django와 같은 전통적인 프레임워크가 비동기 기능을 채택하도록 추진했습니다.
애플리케이션 시나리오:
ASGI는 높은 동시성과 실시간 통신이 중요한 시나리오에서 두각을 나타냅니다.
- 실시간 API: WebSockets를 사용하는 채팅 애플리케이션, 라이브 대시보드, 게임 백엔드.
- 마이크로서비스: 외부 API 또는 데이터베이스와 상호 작용하는 고성능의 반응형 마이크로서비스 구축.
- 데이터 스트리밍: 클라이언트에게 대량의 데이터를 효율적으로 스트리밍하는 API.
- IoT 백엔드: 수많은 동시 IoT 장치 연결 처리.
- 장기 폴링 API: 클라이언트가 지속적인 열린 연결을 유지하지 않고 업데이트를 기다려야 하는 서비스 구축.
결론
ASGI는 파이썬 웹 개발에 있어 혁신적인 도약이며, 비동기 시대로 확고히 나아갔습니다. 표준화되고 프로토콜 비종속적인 인터페이스를 제공함으로써, 전통적인 동기식 접근 방식으로는 어렵거나 불가능했던 고도로 동시적이고 성능이 뛰어나며 확장 가능한 웹 애플리케이션을 구축할 수 있도록 개발자들에게 힘을 실어주었습니다. 비차단 I/O를 촉진하는 우아한 설계와 최신 웹 프로토콜에 대한 기본 지원을 통해 ASGI는 단순한 인터페이스가 아니라 차세대 파이썬 기반 웹 서비스의 초석이며, 전례 없는 속도와 응답성을 가능하게 합니다.
ASGI는 파이썬의 비동기 웹 개발 잠재력을 진정으로 열어주었으며, 그 발전 과정에서 중요한 순간을 기록했습니다.