@senspond
>
파이썬 백엔드 Fast API gunicorn 으로 구동하기 ( WSGI, ASGI, uvicorn 한계 정리)
Fast API Python 기반 백엔드 개발을 해보며 알게 된 내용들을 정리해본 글입니다.
unvicorn / gunicorn 에 대해서 이야기 하기 전에 먼저 웹 서버와 파이썬 애플리케이션간의 인터페이스인 WSGI 와 ASGI 에 대한 이야기가 필요합니다.
웹 애플리케이션을 구동하는 방법에는 WEB Server, CGI, WAS 등등 이 있지만 WSGI / ASGI 라는 파이썬 환경을 위한 인터페이스가 존재합니다.
WSGI는 웹서버와 Python 애플리케이션 사이에 통신하기 위한 인터페이스입니다. 보통의 웹 서버가 Python 애플리케이션을 실행하기 위해서는 WSGI 구현이 필요합니다.
WSGI 서버는 단독으로 사용될 수 있으나 아래와 같은 한계로 흔히 Nginx와 함께 이용됩니다.
DDos등 외부 공격 취약
HTTPS 처리 불가
Static 파일의 전송 효율성
다수의 연결을 효과적으로 처리 불가
WSGI를 계승하여 단점을 보완하고 Python의 AsyncIO 라이브러리를 이용한 비동기 코드를 처리할 수 있다는 장점이 있습니다. 여기 말하는 WSGI의 단점은 요청을 받고 응답을 반환하는 동작이 단일 동기 호출 방식으로 처리된다는 점입니다. 오랜 시간 연결을 유지하는 Websocket 이나 긴 HTTP 요청을 처리하기에 적합하지 않게 됩니다.
ASGI는 이 부분이 단일 비동기 호출이 가능하도록 설계되었다. 따라서 클라이언트로부터 여러 이벤트를 주고받을 수 있으며, 백그라운드 코루틴을 실행할 수 있게 됩니다.
ASGI를 지원하는 파이썬 웹 프레임워크
스탈렛(Starlette)과 패스트API(FastAPI)
쿼트(Quart)
장고(Django) 3.0 이상
기존에 FastAPI를 구동할 때 주로 Uvicorn을 사용했습니다. Uvicorn 은 uvloop와 httptools를 사용해 ASGI(Asynchronous Server Gateway Interface)를 구현한 서버입니다. uvicorn 은 ASGI 프로토콜을 지원하며 cypthon 으로 구현한 uvloop 를 사용하여 비동기 서버를 구현할 수 있게 되어있습니다.
하지만 FastAPI 공식문서에서는 worker를 지정할 경우 uvicorn 보다는 gunicorn 을 사용하는게 좋다고 안내하고 있습니다.
Nevertheless, as of now, Uvicorn's capabilities for handling worker processes are more limited than Gunicorn's.
worker 들을 관리하는 프로세스 매니저로서의 역할을 하기에 uvicorn 이 아직 부족하다고 합니다.
수 많은 요청으로 대규모 트래픽이 발생하는 경우나 여러 CPU 코어를 활용해 병렬처리 하는 경우 한계점을 가지고 있겠습니다. 이어서 이러한 문제점을 개선한 Gunicorn 에 대한 설명입니다.
싱글 프로세스로 동작하는 Uvicorn 의 문제점을 개선해 멀티프로세스를 사용하고 관리할 수 있는 WSGI 서버입니다.
Gunicorn은 WSGI HTTP 서버로, Python 웹 애플리케이션을 병렬로 처리할 수 있는 Pre-fork 워커 모델을 지원합니다.
gunicorn와 uvicorn.workers을 함께 사용하면, FastAPI 애플리케이션을 여러 작업자로 분산하여 처리하고, 동시에 다수의 HTTP 요청을 빠르게 처리할 수 있게 됩니다. 이를 통해 uvicorn의 단점을 Gunicorn으로 보완하고 서버의 성능을 더욱 향상시킬 수 있다고 합니다.
pip install gunicorn
gunicorn -k uvicorn.workers.UvicornWorker --access-logfile ./gunicorn-access.log main:app --bind 0.0.0.0:8000 --workers 2 --daemon
-k uvicorn.workers.UvicornWorker: Uvicorn worker 클래스를 사용합니다.
–access-logfile ./gunicorn-access.log: Gunicorn 로그 파일을 기록합니다.
main:app: main.py의 app을 실행합니다.
-workers 2: worker process의 개수를 설정합니다. 통상 CPU 코어 개수 * 2로 설정합니다!
–daemon: Gunicorn을 백그라운드 데몬 상에서 구동합니다.
–bind 0.0.0.0:8000: 8000 포트에 서버를 연결합니다. 예를 들어 8000포트로 bind 한다면 사용자는 <서버주소>:8000으로 서버에 접속이 가능합니다.
설정 파일로 구동옵션을 좀더 깔끔하게 관리할 수 있는 방법이 있습니다.
gunicorn.conf.py
# gunicorn.conf.py
from datetime import datetime
import os
if not os.path.exists("logs"):
os.makedirs("logs")
os.makedirs("logs/gunicorn")
bind = "0.0.0.0:8200"
workers = 2
worker_class = "uvicorn.workers.UvicornWorker"
reload = True
accesslog = f"./logs/access_{datetime.now().strftime('%Y-%m-%d_%H')}.log"
errorlog = f"./logs/error_{datetime.now().strftime('%Y-%m-%d_%H')}.log"
loglevel = "info"
start.sh
#!/bin/sh
gunicorn manage:app -c gunicorn.conf.py
https://facerain.github.io/fastapi-nginx/
https://blogkr.stocktrees.com/15
안녕하세요. Red, Green, Blue 가 만나 새로운 세상을 만들어 나가겠다는 이상을 가진 개발자의 개인공간입니다.
현재글에서 작성자가 발행한 같은 카테고리내 이전, 다음 글들을 보여줍니다
@senspond
>