FastAPI는 왜 fast한가요? - FastAPI 개발자에게 물어봤습니다.

Hyunsoo Lim·2022년 8월 10일
9
post-thumbnail

시작하기 전에 결론부터

FastAPI 개발자에게 직접 물어봤는데 pip install uvicorn으로 설치하지 말고 pip install "uvicorn[standard]"로 설치하세요. 꼭이요!

++ 추가 (2022.10.11)
추가가 된 건지 지난 번에 놓친 건지는 모르겠지만, 공식 문서 말미에 Optional Dependencies 란에 (이걸 전부 한 방에 설치하고 싶다면) pip install "fastapi[all]" 로 설치하라는 문구가 있다. 앞으로 이걸로 설치해야지.


무엇이 fast한가요?

FastAPI는 이름 그대로 fast하다.

이건 성능면에서나 개발 속도면에서 모두 해당하는 말인데, FastAPI 공식 문서에서 FastAPI의 특징으로 가장 먼저 내세우는 점이기도 하다.

The key features are:

  • Fast: Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic). One of the fastest Python frameworks available.

  • Fast to code: Increase the speed to develop features by about 200% to 300%. *

개발 속도 측면

개발 속도가 빨라질 수 있는 건 상당 부분 pydantic과 OpenAPI 에서 비롯된 편의성 증가 때문이라 생각하는데 이는 이번 프로젝트에서 Django Ninja 를 여러 방식으로 다뤄보면서 여실히 느낀 점이다.
이 포스팅은 성능면에서 왜 fast한지 다루기 위함이 주목적이므로 개발 속도에 관해선 다음 기회에 다루기로 하자.

참고로 Django Ninja는 FastAPI에서 영감을 받아 pydantic과 OpenAPI를 Django에 도입한 프레임워크(혹은 기존 프레임워크의 wrapper)이며, 조금 손봐서 사용한다면 Django의 장점과 FastAPI의 장점을 모두 취할 수 있는 툴이라고 생각한다.

성능 측면

FastAPI는 Node.js 혹은 Go와 비슷한 수준으로 빠른 성능을 자랑한다고 한다.

해당 결과만 보면 Node.js에 앞서고, Go에 필적하는 수준이다. (출처)

여러 포스팅에서 이유를 설명하고 있는데, FastAPI의 개발자인 Sebastián Ramírez의 설명을 보면

FastAPI가 fast한 이유는

  1. Starlette을 쓰기 때문이고, Starlette이 빠른 이유는
    1. Uvicorn을 쓰기 때문이고, Uvicorn이 빠른 이유는
      1. Uvloop을 쓰기 때문이고, Uvloop이 빠른 이유는 (설명과 표에는 나와있지 않지만)
        1. Node.js 비동기IO의 핵심인 libuv를 기반으로 Cython으로 작성되었기 때문

이라고 한다.

Pydantic 역시 Cython으로 컴파일되어 개발 속도 향상 뿐 아니라 성능면에서도 일조하는 걸 알 수 있는데, 참고로 Pydantic V2 Plan 문서를 보면 버전 2에선 Core를 Rust 기반으로 다시 짤거라고 하며, v1.9.1(2022.08.09 현재 최신)에 비해 4~50배 정도 속도가 향상될 거라고 한다. (기대된다! 얼른 Rust 공부도 해야지!!)


다시 FastAPI 자체로 돌아가서..
Starlette > Uvicorn > Uvloop > libuv 로 이어지는 양파 껍질의 구조를 이해하기 위해선 껍질을 한겹한겹 까보면 될 것 같았다.

그래서 갓 생성한 따끈따끈한 가상환경에서 pip install로 각 라이브러리 하나씩만 설치한 뒤 pip list로 같이 설치된 리스트를 살펴보았다.

1. FastAPI & Starlette

FastAPI를 설치하면 다음의 라이브러리들이 같이 설치가 된다.

  • FastAPI 만 설치했을 때

Sebastián Ramírez가 언급한 Pydantic과 Starlette이 보이는데 Uvicorn이나 Uvloop은 보이질 않는다. 어떻게 된 걸까?

FastAPI의 공식문서에 답이 나와있지만 그 전에 Starlette 만 따로 설치해보자.

새로운 환경에서 Starlette 만 설치하고 pip list로 확인해보면 다음과 같은 리스트를 확인할 수 있다. 버전은 조금 다르지만 모두 FastAPI 설치시 같이 설치가 되는 것들이다.

  • Starlette 만 설치했을 때

여전히 Uvicorn이 목록에서 보이질 않는데 FastAPI 설치 후 따로 설치해야 한다는 의미다.

2. Uvicorn

이는 FastAPIStarlette의 공식문서에도 나오는데 문제는 둘이 설치 명령어가 조금 다르다.

  • Starlette 공식문서

  • FastAPI 공식 문서

Starlette과 Django Ninja, 그리고 FastAPI를 설명하는 몇몇 블로그에서는 uvicorn 설치를 아래로 안내하고

1) pip install uvicorn

FastAPI에선 이와 같이 안내한다.

2) pip install "uvicorn[standard]"

Uvicorn의 공식문서에 따르면 이 둘의 차이는

1)은 디펜던시를 최소화한 버전이고, 2)는 Cython 기반의 디펜던시까지 사용하여 더 풍부한 기능을 사용할 수 있는 버전인데 설명만 봐도 1)은 uvloop이 없을 것 같고 2)는 다 있을 것 같다.

그래서 각각의 명령어로 설치해 비교해보면 다음과 같다.

  • pip install uvicorn

  • pip install "uvicorn[standard]"

잘못 사용할 수도 있겠는데?

Uvloop과 libuv를 더 살펴보기 전에 이 시점에서 의문이 들었다.

Sebastián Ramírez의 말로는 FastAPI가 fast한 이유가 결국엔 uvloop, 더 나아가 그 속의 libuv를 사용하기 때문인데, pip install uvicorn 으로 설치하면 uvloop을 쓸 수 없어 성능상의 이점을 전혀...까지는 아니더라도 상당 부분 못 누리는 거 아닐까?

그래서 Sebastián Ramírez 에게 직접 물어보았고 다음과 같은 답을 얻었다.

그래 니 말이 맞고, 성능을 최대치로 누리려면 리눅스 머신에서, "uvicorn[standard]" 로
설치해야해.
구 버전 Uvicorn은 uvloop을 디폴트로 같이 설치했었는데, 지금은 바뀌었고 문서에 반영이 안 된 곳도 있을거야.

답변을 통해 Starlette 과 Django Ninja에서 1)로 안내하는 이유도 알 수 있었다.

문제는 FastAPI와 관련된 예전 블로그들에서 잘못된 안내를 하고 있고, 공식문서 대신 그걸 참조하는 경우 성능상 이점을 제대로 못 누릴 수가 있는데, FastAPI를 설치할 때 자동으로 "uvicorn[standard]"도 설치하면 되지 않나 싶어 물어보았다.

다른 ASGI도 사용할 자유를 주기 위해서일 거라 짐작하긴 했는데, 다음과 같은 답변이 왔다.

니 말에 더해 serverless까지 고려해서 ASGI 설치는 자유에 맡겼어

3. Uvloop & 4. libuv

FastAPI 개발자와의 대화를 통해 의문은 대부분 해결되었지만, 양파 껍질 까는 김에 조금 더 까보자.

pip 로 uvloop을 설치한 뒤 라이브러리 리스트를 보면 다음과 같다.

  • pip install uvloop

libuv이 없다.

Cython이나 라이브러리 빌드하는 방식을 정확히 모르겠지만, 아마 libuv가 따로 안 보이는 이유는 Cython 으로 짜여진 uvloop이 빌드할 때, C++로 짜여진 libuv를 같이 말아넣기 때문은 아닌가 싶다.

uvloop 공식 문서를 참조해 git repo를 clone해 폴더 및 파일 구조를 보고 유추할 수가 있는데, 대략적인 구조는 아래와 같다.

uvloop
├── uvloop
      ├── includes
             ├── loop.pyi        # 스텁 파일(?)
             ├── loop.pxd       # Cython 모듈에 포함될 수 있는 Cython 선언을 저장
             └── loop.pyx       # Cython src를 C/C++로 변환
├── vender
      ├── libuv
             ├── scr
                    ├── asycn.c       # C/C++ src
                    └── core.c         # C/C++ src

git clone --recursive git@github.com:MagicStack/uvloop.git

해당 repo를 clone 하는 명령어인데, 소스 내부의 문서에서 다음과 같이 설명한다.

--recursive 를 붙여야 libuv 깃헙에서 libuv소스도 가져오니 꼭 붙이세요!

즉, --recursive를 붙이지 않는다면 vender 폴더 안의 libuv를 가져오지 않고 libuv를 이용해 빌드를 할 수 없다는 이야기.

그리고 uvloop을 (libuv와 함께) 빌드하기 위해선 Cython과 Python 3.7 이상이 필요한데, 이 때문에 Uvicorn 설치를 1)minimal과 2)standard형 두 가지로 나눈 게 아닌가 싶기도 하다.

스샷은 참고로 uvloop 내의 loop.pyx 파일의 일부인데 Cython 코드를 처음봐서 신기방기했다.
python 모듈도 import 하는 와중에 include도 보이고.


따뜻한 개발자

여담으로 Sebastián Ramírez는 무척이나 따뜻한 사람 같았다. 위의 질의를 나눈 날 SNS에 다음과 같이 글을 남겼는데, 물론 나와 나눈 대화 때문만은 아니었겠지만 나에게 하는 이야기 같아 무척 기분이 좋았다.

솔직히 FastAPI를 직접 쓴 게 아니라 차용한 Django Ninja를 쓰면서도 FastAPI의 방식에 개발자를 편하게 도와주려는 철학이 내재된 것 같다고 생각했는데, 만든 사람의 친절함이 자연스레 녹아든 게 아닐까 싶다. 나 역시 이렇게 쩌는 실력을 가진 따뜻한 마음의 개발자가 되고 싶다.

profile
잡식형 괴발자

4개의 댓글

comment-user-thumbnail
2022년 10월 10일

저도 왜 [standard]로 설치하라고 하는지 의문이었는데 이제야 좀 알 것 같네요 좋은 내용 감사합니다!!

1개의 답글
comment-user-thumbnail
2022년 11월 8일

계속해서 파고드는 모습이 멋집니다!

1개의 답글