Python 3.9.5을 사용합니다.
pip 22.1.1을 사용합니다.
최근 FastAPI
에 대한 인기가 많이 높아졌다. FastAPI
는 나온지 얼마되지도 않았을 때부터도 인기가 굉장했다. 여담이지만, FastAPI
자체를 개발한 개발자가 FastAPI
를 만든 지 1년 반 정도 되었을 무렵, FastAPI
를 3년간 써본 개발자를 찾는 공고를 보고 트위터에 올렸을 정도로 회사에서의 인기가 굉장히 높다. 한국이든 외국이든 개발자 역량보다 프레임워크만 달달 외워서하는 채용은 만연한가 보다
그럼 FastAPI
는 왜 인기가 좋은 것일까?? 개인적으로 생각했을 때 두 가지 이유가 있다.
첫번째는 기존 파이썬 웹 프레임워크들 대비에 성능이 훨씬 더 좋다. 비동기 통신을 기반으로 하기 때문에 FastAPI
로 서버를 만들면 비동기적인 연산을 쉽게 할 수 있다. 아래에 나오겠지만 flask
나 django
는 기본적으로 동기 통신을 기반으로 하기 때문에 아무리 서버 내부에서 요청마다의 쓰레드를 구동하고 처리한다해도 효율이 나지 않는다.
두번째는 '파이썬'이라서 이다. 가장 중요한 이유인 것 같다. 사실 FastAPI
가 python 웹 프레임워크 중에서 성능이 좋다일 뿐이지, 절대적으로보면 엄청난 high performance를 보여준다고 할 수는 없다. 이미 golang과 rust가 web개발에 들어서고 있기 때문에 성능으로는 비교가 안된다. cpu 효율, 메모리 효율 뭐 하나 이길 수가 없다. 그런데, 사실 요즘 application이 무슨 성능이 크게 중요하겠나, 다들 성능 그닥인 거 알지만 그냥 쓰기 편하니까 또는 배웠던 프레임워크니까 성능은 데브옵스가 알아서 하라고하고 코드를 만든다. 그렇다면 왜 FastAPI
를 쓰는 것인가?
가장 큰 이유는 python
이라고 생각한다. 아주 단순한 이유지만, 매우 강력하다. python
이기 때문에 ML 모델도 쉽게 서빙할 수 있고, 다양한 python 라이브러리들을 유연하게 사용할 수 있다. 또한, python
이기 때문에 생산성이 굉장히 빠르고, 쉽고 빠르게 코드를 만들 수 있다. 성능의 꼬리표를 달던 python
진영에 FastAPI
는 가뭄의 단비이며, 새로운 구세주라고 생각한다.
최근 MSA 환경이 발전하면서 대기업을 중심으로 MSA 아키텍처들이 속속히 도입되고 있다. 그 중 golang과 python이 많은 사랑을 받는데, golang은 성능과 없는게 없는 클라우드 SDK 덕분에 자주 사용된다. python은 ML 모델을 서빙하는 경우나 python과 관련된 lib을 써야하는 경우, 대부분 FastAPI
를 선호한다. API들 끼리의 요청을 빠르게 처리할 수 있고, 가벼우며, 쉽고 빠르게 코드를 개발할 수 있기 때문에 MSA 구조와 딱 잘 맞는다. 물론 그래봤자 한국은 어떻게해서든 spring으로 하려고 할 꺼다
python3가 설치되었다는 것을 가정하고 시작한다. 파이썬 어플리케이션은 virtualenv을 사용해 개발된다. 파이썬 자체가 워낙 모듈 간의 호환이 안좋고, 하위 호환성도 잘 못맞추는 경우가 수두룩하기 때문에 모듈 간의 버전 충돌이 발생하면 그야말로 지옥의 시작이다.
따라서, global하게 python 패키지들을 설치하기 보다는 프로젝트마다 local로 패키지를 설치해주는 것이 좋다. 이것을 가능하게 해주는 것이 바로 virtualenv
이다. virtualenv
를 통해서 해당 프로젝트의 의존성을 local로 관리할 수 있고, 모듈 버전 관리를 유연하게 할 수 있다.
프로젝트에 들어가서 다음의 명령어를 치면 가상 환경이 설치된다.
python3 -m venv venv
venv
라는 모듈을 사용해서 venv
라는 디렉터리를 만들겠다는 것이다. 생성된 가상 환경 폴더 venv
에는 파이썬 인터프리터가 설치된 lib
폴더와 가상 환경 내에서 상호 작용(가상 환경 활성화/비활성화) 등이 필요한 파일을 저장하는 bin
폴더가 있다.
여기서 끝난 것이 아니라, 가상 환경을 시작해주어야 한다. 이를 위해서 activate가 필요하다.
source venv/bin/activate
가상 환경이 활성화되면 해당 환경 내에 있는 파이썬 인터프리터와 패키지를 기본으로 사용한다. 가상 환경이 제대로 활성화되었다멵, 스크립트 프롬프트 앞에 표시된다.
(venv) machine:/project
가상 환경을 비활성화하는 방법은 다음과 같다.
deactivate
스크립트 프롬프트 앞에 표시된 내용이 사라진 것을 볼 수 있다.
machine:/project
다시 가상 환경을 activate
시키도록 하자.
source venv/bin/activate
다음의 명령어를 입력하도록 하자.
pip3 install fastapi
잘 설치가 되었다면 다음의 메세지가 나온다.
nstalling collected packages: typing-extensions, idna, sniffio, anyio, starlette, pydantic, fastapi
Successfully installed anyio-3.6.2 fastapi-0.95.2 idna-3.4 pydantic-1.10.7 sniffio-1.3.0 starlette-0.27.0 typing-extensions-4.5.0
이 후 fastapi
를 삭제하고 싶다면 다음의 명령어를 입력하면 된다.
pip uninstall fastapi
현재 프로젝트에 설치된 모든 패키지 목록을 파일로 저장하려면 다음과 같이 freeze
명령과 >
연산자를 사용하면 된다.
pip freeze > requirements.txt
>
는 pip freeze
의 결과를 requirements.txt
파일에 저장한다. requiremnets.txt
를 보면 local에 설치된 패키지들을 볼 수 있다.
추후에 이 reuqirements.txt
를 사용하여 local에 패키지를 설치할 수 있다. 해당 명령어를 사용하면 된다.
pip install -r requirements.txt
python web application은 재밌게도 WSGI라는 것을 사용한다. WSGI를 말하기 전에 CGI에 대해서 먼저 말해야하는데, CGI는 Common Gateway Interface로 web server과 application server 간의 데이터를 주고 받는 interface이다. web server는 단순한 static 처리(file, image, script, css를 던져누는 기능)을 하지만, 동적인 기능(form처리, 인증, 인가 등)는 web application server에서 처리해야한다. java, python, golang, nodejs 등의 서버가 바로 web application server로 분류되며, golang과 nodejs는 web server를 기본적으로 내장하고 있어 따로 CGI를 설정해줄 필요가 없어, 기본 web 라이브러리만으로도 server가 동작한다. 물론, 내장된 web 라이브러리를 다 까보면 CGI를 구현하고 있는 것을 알 수 있다.
그러나, c,c++,java,python과 같이 web server를 내장하지 않은 언어들은 web server가 필요하고, web server와 해당 언어로 만들어진 코드 간의 interface가 필요하다. 이 interface가 바로 CGI이고, CGI는 어떤 코드를 일컫는게 아니라, 프로토콜, 즉 interface이다. 이에 대한 구현체는 언어마다 상이하고, 누가 만들었는가에 따라서도 상이하다. 중요한 것은 CGI와 web server를 연결하여 우리가 아는 backend server가 되는 것이다.
client <--HTTP--> web server <--HTTP--> CGI(interface) <--Convert HTTP to language--> c,c++,python,java etc
WSGI는 CGI의 python version 개념으로 web server(nginx, 아파치 등등)과 web application server(flask, django, fastapi)가 서로 통신하기 위한 인터페이스이다. python으로 된 web application server의 python 스크립트를 실행시켜주고, http 데이터를 python 데이터로, python 데이터를 http로 변환해준다고 생각하면 된다.
참고로, WSGI든 이후에 배울 ASGI든 web server를 따로 필요로 하진 않는다. 현재에는 그 자체로도 web server 기능을 할 수 있기 때문이다. 물론 web server와 함께 사용하여 안전하고, 효율적인 구성이 가능하다는 장점이 있다.
client <--HTTP--> web server <--HTTP--> WSGI(Protocol) <--Convert HTTP to Python object--> python web application server
인터페이스, 즉 추상적인 프로토콜이기 때문에 이를 구현한 구현체가 필요한데, 이것이 바로 gunicorn
이다. WSGI의 구현체가 바로 gunicorn
으로 gunicorn
을 통해 web application server를 동작시켜 web server와 통신하고, client의 요청을 처리할 수 있다. (물론, web server 없이 gunicorn
으로 web application server를 동작시켜 client의 요청을 동적으로 처리할 수 있다.)
client <--HTTP--> web server <--HTTP--> Gunicorn <--Convert HTTP to Python object--> python web application server
이 WSGI
을 사용한 프레임워크가 바로 flask
와 django
이다.(물론 django 3.0에서부터 ASGI
를 지원하긴 한다) WSGI
의 가장 큰 단점은 WSGI
가 동기적으로 동작하기 때문에 한 번에 하나의 요청만 처리하며, 응답이 즉시 반환된다는 전재를 한다. 이는 롱 풀링, 웹소켓과 같은 HTTP 연결이 장시간 연결되는 경우 처리할 방법이 없다. 또한, WSGI
는 동기 전용이기 때문에 멀티스레드 연결 풀을 사용하더라도 응답이 반환될 때까지 각 연결이 차단된다.
WSGI
가 나올 때까지만 해도 python2를 사용했으며, asyncio
와 같은 비동기 라이브러리가 없었다. 이후 시간이 지나 비동기 처리 방식이 발달하고 fastapi
가 등장하게 된다.
fastapi
는 조금 독특한데, WSGI의 업그레이드 버전인 ASGI
를 사용한다. ASGI
는 WSGI
의 방식에서 크게 다를 것은 없고, 비동기 방식인 asyncio
를 사용한다는 것이다. 그렇기 때문에 요청에 있어 훨씬 효율적으로 처리할 수 있게 된 것이다.
client <--HTTP--> web server <--Async HTTP--> ASGI(Protocol) <--Async Convert HTTP to Python object--> python web application server
ASGI
를 사용할 때 async
함수와 최대한 비동기 친화적인 라이브러리를 사용하는 것이 좋다. async
를 사용하는 습관을 들이면 상당한 효과를 볼 수 있다. 동기적인 함수에 대한 장시 호출은 전체 호출 체인을 차단하게 되므로 비동기 사용의 장점이 모두 사라진다.
오랜 시간동안 동기 호출을 쓸 수 밖에 없다면 asyncio.run_in_executor
를 사용해 스레드 또는 프로세스 풀에 대한 호출을 맡긴다. 가령, web application server에서 remote web site를 호출하는 경우 스레드를 사용하거나 aiohttp
라이브러리로 http 요청을 수행하는 것이 좋다.
ASGI
또한 인터페이스이지 구현체는 아니다. 구현체가 바로 uvicorn
이다. fastapi
는 uvicorn
을 사용하여 web application server를 구동하여 web server와 비동기 통신을 이루는 것이다.
client <--HTTP--> web server <--Async HTTP--> Uvicorn <--Async Convert HTTP to Python object--> python web application server
이제 fastapi와 uvicorn을 설치해보고 실행시켜보도록 하자.
pip install fastapi uvicorn
api.py
라는 파일을 만들어 FastAPI에 새 인스턴스를 생성해보도록 하자.
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def greeting() -> dict:
return {
"message": "hello"
}
다음의 api.py server를 실행하기위해서 uvicorn
을 실행해보도록 하자.
uvicorn api:app --port 9596 --reload
uvicorn을 실행할 때 지정하는 인수는 다음과 같다.
1. file:instance
: FastAPI 인스턴스가 존재하는 파이썬 파일과 FastAPI 인스턴스를 가지고 있는 변수를 지정한다.
2. --port
: 어플리케이션에 접속할 수 있는 포트 번호를 지정
3. --reload
: 파일이 변경될 때마다 어플리케이션을 재시작
실행 시 다음의 로그가 발생한다.
INFO: Application startup complete.
다음의 명령어로 요청을 보내면
curl localhost:9596/
다음의 환영 메시지를 받을 수 있다.
{"message":"hello"}
기본적인 FastAPI
설명과 실행방법을 소개하였다.
Python 백엔드 공부하다가 들어왔는데 설명이 너무 이해하기 쉽네요,, 감사함니다..!