はじめに
こんにちは、アレクサの音量は色々悩んだ結果3なニシグチです。
突然ですが、今「麻雀何切るアプリ」を開発しておりまして、
バックエンドのフレームワークにFastAPIを採用しました。
今まで業務ではバックエンドのフレームワークにDjangoを使っていたんですが、
せっかく個人開発なので、新しいフレームワークに触れてみたいと思い採用しました。
その中で、FastAPIで使われている Uvicorn や ASGIサーバー という言葉を目にしました。
最初に見た時は、正直 Gunicorn のFastAPI版みたいなものかなと思っていました。
ただ、調べていくうちに、
そもそも自分の中でGunicornとDjangoの関係や、
WSGIサーバーについての理解も浅かったことに気づきました。
なので今回は、FastAPIを触る前提知識として、
WSGIサーバーとASGIサーバーについて再整理してみます。
これまでの自分の理解
Djangoには開発用サーバーを立ち上げるコマンドがあります。
python manage.py runserver
そのため最初は、Django自体がアプリケーションサーバーのような役割も持っているのかなと思っていました。
ただ、実際にはDjangoは本番環境でリクエストを受け続けるためのサーバーというより、
リクエストを処理するアプリケーション本体を作るためのフレームワークですよね。
そこで本番環境では、Djangoの開発用サーバーをそのまま使うのではなく、
NginxやApacheの後ろにGunicornのようなWSGIサーバーを置いて、
Djangoで書いたアプリケーションを呼び出す構成がよく使われます。
DjangoとGunicorn、WSGIサーバーの関係は、以前まで以下のような理解でした。
クライアント
↓
Nginx / Apache
↓
Gunicorn
↓
Django
ここでは、Nginx / Apache がWebサーバー、GunicornがWSGIサーバー、DjangoがPythonアプリケーションという理解でした。
その時に初めてWSGIサーバーという言葉を知って、調べた時は以下のように理解していました。
クライアントがWebサーバーへHTTPリクエストを投げる。
そのリクエストをDjangoがそのまま理解できるわけではない。
だから、Djangoに理解できる形へ通訳するためにWSGIサーバーがいる。WSGIサーバーは、HTTPリクエストの内容をPythonで扱える形式に変換して、
Djangoのアプリケーションを呼び出している。
だからApacheやNginxとDjangoの間にWSGIサーバーが必要になる。
この理解は大きく外れていないと思うんですが、
今振り返ると、少し「通訳」というイメージに寄せすぎていた気がします。
Gunicornは単にリクエストを変換しているだけではなく、
DjangoなどのPython Webアプリケーションを本番環境で動かすための
アプリケーションサーバー、またはWSGIサーバーとして捉える方がしっくりきました。
だからASGIサーバーという言葉を聞いた時に、
Gunicorn ≒ Uvicorn?
WSGIサーバー ≒ ASGIサーバー?
ASGIサーバーはWSGIサーバーの親戚?
と思っていました。
これ、ざっくりした理解としてはそこまで外れてないんですが、
「ASGIはWSGIの上位互換」みたいに捉えると少し違いそうです。
WSGI、ASGIはどちらもPythonのWebアプリケーションとサーバー側をつなぐための仕様です。
ただ、WSGIは同期的なHTTPリクエスト/レスポンスを扱う前提で広く使われてきた仕様で、
ASGIは非同期処理やWebSocketなども扱いやすいように作られた仕様です。
なので自分の中では、
「WSGIの代わりにASGIがある」
というより、
「DjangoやFastAPIをサーバーから呼び出すための仕様として、WSGI系とASGI系がある」
くらいに捉えるとしっくりきました。
WSGIとはなんだ
そもそもWSGIは Web Server Gateway Interface の略です。
PythonのWebアプリケーションと、それを実行するサーバー側をつなぐための標準化されたインターフェースです。
自分は最初、WSGIを「ApacheやNginxとDjangoをつなぐためのもの」くらいに考えていました。
ただ、もう少し正確に言うと、
特定のWebサーバーや特定のPythonフレームワークに依存しすぎないように、
Python Webアプリケーションとサーバーの間の呼び出し方を共通化した仕様、という理解の方が近そうです。
WSGIがあることで、DjangoやFlaskなどのフレームワークと、
GunicornやuWSGIなどのサーバーを組み合わせて使えるようになります。
ここをちゃんと理解していませんでした。
今までPythonのWebアプリケーションフレームワークはDjangoしか使ったことがなかったので、
そもそも「フレームワークとサーバーの組み合わせでどちらかが使えなくなる」という発想があまりありませんでした。
Djangoで書いたViewやModelなどのコードは、あくまでアプリケーションロジックです。
本番環境では、そのDjangoアプリケーションをGunicornのようなWSGIサーバーが起動し、
HTTPリクエストをWSGIの仕様に沿ってDjangoへ渡します。
Django側は、その情報をもとにリクエストオブジェクトを作り、
URLルーティングやViewの処理を実行します。
なので、Gunicornは単なる「通訳」というより、
Djangoアプリケーションを本番環境で動かすための
アプリケーションサーバー / WSGIサーバー と捉えるのがイメージ的にはよさそうです。
話戻ってWSGIサーバーとASGIサーバーの比較
ここまで整理すると、
「じゃあFastAPIでASGIサーバーが使われるのも、DjangoでGunicornを使うのと似たような話なのでは?」
と思いました。
実際、かなり近い話ではありそうです。
Django + Gunicorn の場合は、GunicornがWSGIサーバーとしてDjangoアプリケーションを呼び出します。
クライアント
↓
Nginx / Apache
↓
Gunicorn
↓ WSGI
Django
FastAPI + Uvicorn の場合は、UvicornがASGIサーバーとしてFastAPIアプリケーションを呼び出します。
クライアント
↓
Nginx / Apache
↓
Uvicorn
↓ ASGI
FastAPI
なので最初は、以下のように捉えていました。
| フレームワーク | 呼び出し仕様 |
|---|---|
| Django | WSGI |
| FastAPI | ASGI |
ただ、これは少し雑でした。
実はDjangoはWSGIだけではなく、ASGIにも対応しています。
つまり、DjangoをGunicornでWSGIアプリケーションとして動かすこともできるし、
UvicornでASGIアプリケーションとして動かすこともできます。
なので正確には、以下の理解の方がよさそうです。
| フレームワーク | 整理 |
|---|---|
| Django | WSGIでもASGIでも動かせる |
| FastAPI | 基本的にASGIアプリケーションとして動かすことを前提にしたフレームワーク |
FastAPIとUvicornで考える
今回自分が触っているFastAPIでは、基本的にASGIサーバーとしてUvicornを使います。
開発時によく見る起動コマンドも、以下のような形です。
uvicorn main:app --reload
今まではこのコマンドを見ても、
「FastAPIを起動しているんだな」
くらいにしか思っていませんでした。
ただ、今回WSGIとASGIを整理してみると、
このコマンドはUvicornというASGIサーバーが、
main.py にある app というFastAPIアプリケーションをASGIの仕様に沿って呼び出している、
ということなんだと理解できました。
Django + Gunicorn の構成でいうと、
Gunicorn
↓ WSGI
Django
だったものが、FastAPIでは、
Uvicorn
↓ ASGI
FastAPI
になるイメージです。
ここまで整理すると、最初に思っていた
GunicornのFastAPI版がUvicorn
という理解も、ざっくりした入り口としては悪くなかった気がします。
ただし、正確にはGunicornとUvicornは同じものではなく、
それぞれ対応しているインターフェースが違います。
| サーバー | 主な役割 |
|---|---|
| Gunicorn | 主にWSGIアプリケーションを動かすサーバー |
| Uvicorn | ASGIアプリケーションを動かすサーバー |
そして、WSGIとASGIも親子関係というより、
Python Webアプリケーションをサーバーから呼び出すための別系統の仕様として捉える方がしっくりきました。
まとめ
FastAPIを触る中で Uvicorn や ASGIサーバー という言葉を見たことをきっかけに、
WSGIサーバーとASGIサーバーについて再整理してみました。
今回整理した内容を自分の言葉でまとめると、以下です。
| 対象 | 今回の整理 |
|---|---|
| Django / FastAPI | Webアプリケーション本体を作るためのフレームワーク |
| Gunicorn / Uvicorn | Python Webアプリケーションを外部から利用できるように動かすアプリケーションサーバー |
| Gunicorn | 主にWSGIアプリケーションを動かすサーバー |
| Uvicorn | ASGIアプリケーションを動かすサーバー |
| WSGI | 同期的なHTTPリクエスト/レスポンスを扱う前提で広く使われてきた仕様 |
| ASGI | 非同期処理やWebSocketなども扱いやすいように作られた仕様 |
| Django | WSGIでもASGIでも動かせる |
| FastAPI | 基本的にASGIアプリケーションとして動かすことを前提にしたフレームワーク |
最初は Uvicorn を「GunicornのFastAPI版」くらいに捉えていました。
ざっくり入口としてはそこまで外れていないかもしれませんが、
正確には、GunicornとUvicornはそれぞれ対応している仕様が違うアプリケーションサーバーでした。
まだFastAPIを触り始めたばかりなので、
実際にアプリを作りながら、ASGIやUvicorn周りの理解も深めていこうと思います。