← プログラミングページの先頭へ

Gunicorn + Uvicorn: Python Web サービス展開

Gunicorn + Uvicorn は、Python Web プロジェクトの一般的な運用環境の組み合わせです。

その中には:

  • Gunicorn: プロセス管理、Worker ライフサイクル、シグナル処理、およびプロセスレベルの同時実行性を担当します。
  • Uvicorn: ASGI アプリケーションの実行と、HTTP、非同期 I/O、および ASGI プロトコル通信の処理を担当します。
  • Django / FastAPI: ルーティング、ビジネス ロジック、データベース アクセスなどのアプリケーション機能を担当します。
  • Nginx: 通常はリバース プロキシとして使用され、HTTPS、静的リソース、リクエスト転送などを担当します。

典型的なアーキテクチャ:

Client
   ↓
Nginx (Reverse Proxy)
   ↓
Gunicorn (Master Process)
   │
   ├── Uvicorn Worker 1 ──→ Django ASGI
   ├── Uvicorn Worker 2 ──→ Django ASGI
   ├── Uvicorn Worker 3 ──→ Django ASGI
   └── Uvicorn Worker 4 ──→ Django ASGI

Gunicorn は Worker プロセスを管理しますが、実際の ASGI リクエストの処理は Worker で実行されている Uvicorn によって行われます。

1. WSGI および ASGI

WSGI

WSGI (Web Server Gateway Interface) は、Python Web サーバーとアプリケーション間の標準インターフェイスです。

従来の Django は通常、WSGI を使用します。

Client
   ↓
Nginx
   ↓
Gunicorn (WSGI Worker)
   ↓
Django WSGI Application

開始:

gunicorn config.wsgi:application

WSGI は主に同期リクエスト応答モデルを中心に設計されています。

ASGI

ASGI(Asynchronous Server Gateway Interface)は、非同期通信をサポートするインターフェース規格です。

ASGI は以下をサポートします。

  • HTTP リクエスト。
  • 非同期処理。
  • WebSocket プロトコル インターフェイス。
  • 長時間接続のシナリオ。
  • ASGI Lifespan などのプロトコル拡張。

典型的なアーキテクチャ:

Client
   ↓
Nginx
   ↓
Uvicorn (ASGI Server)
   ↓
Django / FastAPI

開始:

uvicorn config.asgi:application

WSGI 対 ASGI

特長WSGIASGI
主なプログラミングモデル同期する同期および非同期をサポート
HTTPサポートサポート
WebSocketネイティブではサポートされていませんプロトコル層のサポート
長い接続一定の制限がありますより適切な
async/awaitネイティブではサポートされていませんネイティブサポート
Djangoサポートサポート
FastAPI通常は使用されませんネイティブ ASGI

注: ASGI サーバーは WebSocket をサポートしますが、これは、Django に付属する ASGI アプリケーションが WebSocket を直接処理できることを意味するものではありません。

Django プロジェクトでは通常、WebSocket サービスを実装するために Django Channels または他の ASGI ルーティング コンポーネントが必要です。

2. Uvicorn

UvicornはPython ASGI Serverです。

主に以下を担当します。

  • HTTP接続を受信します。
  • HTTP リクエストを解析します。
  • ASGI Application に電話してください。
  • 非同期イベントループを管理します。
  • ASGI HTTP/WebSocket プロトコルを処理します。
  • HTTP 応答をクライアントに送信します。

動作原理

HTTP Request
     ↓
Uvicorn
     ↓
ASGI Scope / Receive / Send
     ↓
Django ASGI Application
     ↓
View / Business Logic
     ↓
ASGI Response
     ↓
Uvicorn
     ↓
HTTP Response

Uvicorn はイベント ループを使用して非同期タスクを処理し、ネットワークまたは他の非同期 I/O を待機している間も他のリクエストの処理を続行できます。

開発環境を起動する

uvicorn config.asgi:application --reload

--reload はコードの変更を監視し、アプリケーションを自動的に再起動します。主に開発環境で使用されます。

本番環境を開始する

uvicorn config.asgi:application \
    --host 0.0.0.0 \
    --port 8000 \
    --workers 2

--workers は複数の Uvicorn Worker プロセスを開始できます。

注:--reloadと--workersは同時に使用できません。

したがって、Uvicorn は単一プロセス サーバーであるだけでなく、特定のマルチプロセス管理機能も備えています。

3. Gunicorn

Gunicorn (Green Unicorn) は Python WSGI HTTP Server であり、成熟したプロセス管理機能も提供します。

互換性のある Worker タイプを使用する場合、ASGI Server は Gunicorn 経由でも管理できます。

主な機能:

  • 複数の Worker プロセスを開始します。
  • Workerのステータスを監視します。
  • Worker はクラッシュ後に自動的に再起動します。
  • 正常なシャットダウンと再起動。
  • Unix信号処理。
  • リクエストのタイムアウトと Worker ヘルス監視。
  • ログ管理。
  • Worker リクエストの最大数を制御します。

Master / Workerモデル

Gunicorn Master
       │
       ├── Worker 1
       ├── Worker 2
       ├── Worker 3
       └── Worker 4

Master はプロセスの管理を担当します。

Worker は実際のリクエストを処理する責任があります。

Worker タイプが異なれば、同時実行モデルも異なります。次に例を示します。

  • sync: Worker を同期します。
  • gthread: スレッド Worker。
  • gevent: 協調同時実行性 Worker。
  • UvicornWorker:ASGI Worker。

Gunicorn 自体は、使用される Worker のタイプに応じて、アプリケーションが必ずしも同期であるか非同期であるかを決定しません。

4. Gunicorn + Uvicorn Worker

Django ASGI アプリケーションの場合:

Gunicorn Master
       │
       ├── Uvicorn Worker 1
       ├── Uvicorn Worker 2
       ├── Uvicorn Worker 3
       └── Uvicorn Worker 4

各 Uvicorn Worker は独立したオペレーティング システム プロセスであり、独自のイベント ループと ASGI アプリケーション インスタンスを実行します。

インストール

pip install gunicorn uvicorn uvicorn-worker

始める

gunicorn config.asgi:application \
    -k uvicorn_worker.UvicornWorker \
    --workers 4 \
    --bind 0.0.0.0:8000

パラメータの説明:

パラメータ機能
config.asgi:applicationDjango ASGI アプリケーション入口
-kWorkerタイプを指定してください
--workersWorker プロセス数
--bindリスニングアドレスとポート

uvicorn.workers の廃止

古い書き方:

gunicorn config.asgi:application \
    -k uvicorn.workers.UvicornWorker

uvicorn.workers は Uvicorn によって正式に非推奨になりました。

スタンドアロンの uvicorn-worker パッケージを使用することをお勧めします。

gunicorn config.asgi:application \
    -k uvicorn_worker.UvicornWorker

これにより、非推奨のモジュールへの依存関係が軽減されます。

5. 同期および非同期の同時実行モデル

同期Worker

従来の Gunicorn sync Worker は通常、一度に 1 つのリクエストのみを処理します。

Worker 1 → Request A
Worker 2 → Request B
Worker 3 → Request C

Request A が時間のかかる I/O の同期を実行している場合、そのリクエストを担当する Worker は他のリクエストを同時に処理できない可能性があります。

非同期 Worker

Uvicorn イベント ループを使用すると、非同期タスクは I/O を待機している間に実行権を渡すことができます。

Uvicorn Worker
      │
      ├── Request A → await DB
      ├── Request B → await HTTP
      └── Request C → Processing

プロセスは、適切な条件下で複数のリクエストを同時に処理できます。

しかし、それは区別する必要があります。

  • 同時実行性 (Concurrency): 複数のタスクが時間内に交互に進行します。
  • 並列 (Parallelism): 複数のタスクが実際に同時に実行されます。

非同期は主に I/O 待機シナリオの同時実行機能を向上させますが、CPU の集中的な計算を自動的に高速化するわけではありません。

CPU intensive and I/O intensive

種類例Common optimization methods
CPU集中型Image processing, massive Python calculationsマルチプロセス、タスクキュー、特化したコンピューティングサービス
I/O集中型HTTP request, database waitingAsynchronous I/O, appropriate concurrency
ハイブリッドData processing + network callsOptimize based on bottleneck combinations

たとえば:

async def get_data():
    response = await async_client.get(
        "https://example.com"
    )
    return response.json()

HTTP Client が真の非同期 I/O をサポートしている場合、イベント ループはネットワーク応答を待機している間も他のタスクの処理を続行できます。

ただし:

async def get_data():
    response = requests.get(
        "https://example.com"
    )
    return response.json()

ここでの requests.get() は、イベント ループをブロックする可能性がある同期ブロック呼び出しです。

したがって、が関数を async def として宣言しても、その関数内の操作が自動的に非ブロック操作になることを意味するわけではありません。

6. Django ASGI and asynchronous support

Django は、同期 View および非同期 View をサポートします。

同期View

def get_data(request):
    result = calculate_data()
    return JsonResponse(result)

非同期 View

async def get_data(request):
    result = await fetch_remote_data()
    return JsonResponse(result)

ただし、Django が ASGI を通じて実行される場合でも、同期 View は依然として同期実行メカニズムを通じて実行する必要があり、これには通常、スレッドの適応が含まれます。

Django ORM

Django は、部分的に非同期の ORM メソッドを提供します。

user = await User.objects.aget(id=1)

そして:

async for user in User.objects.all():
    print(user.username)

ただし、Django ORM のすべての機能が完全な非同期サポートを備えているわけではありません。

特に、トランザクション操作と特定のデータベース接続管理動作にはさらなる注意が必要です。

Asynchronous support for DRF

標準の DRF APIView および GenericAPIView の使用方法は、主に同期処理を中心に設計されています。

次のものだけを含めないでください。

def get(self, request):
    ...

Change to:

async def get(self, request):
    ...

完全な DRF リクエスト処理リンクがすでに非同期をサポートしていると仮定してください。

非同期 API が必要な場合は、DRF のバージョン、拡張ライブラリ、具体的なビューの実装に基づいて互換性を確認する必要があります。

通常の Django REST API の場合、同期された View と ASGI Server を使用することが許容される展開方法です。

ただし、これは、同期リクエストがネイティブ非同期 View の同時実行性の利点をすべて直接得られるという意味ではありません。

7. Gunicorn共通構成

Typical startup command:

gunicorn config.asgi:application \
    -k uvicorn_worker.UvicornWorker \
    --workers 2 \
    --bind 0.0.0.0:8000 \
    --timeout 60 \
    --graceful-timeout 30 \
    --max-requests 1000 \
    --max-requests-jitter 100 \
    --access-logfile - \
    --error-logfile -

コアパラメータ

パラメータ機能
workersWorkerプロセス数
bindListen on IP/port
timeoutWorker 無応答タイムアウト
graceful_timeout正常なシャットダウンまたは再起動の待ち時間
max_requestsWorker 一定数のリクエストを処理した後に再起動します
max_requests_jitterランダムなオフセットを再起動しきい値に追加します
accesslogHTTP アクセスログの場所
errorlogError log location
loglevelLog level
preload_appPreload apps in Master
worker_tmp_dirWorker 一時ファイルディレクトリ

timeout および graceful_timeout

timeout:

--timeout 60

これは主に、Master のヘルスチェックに一定時間以上正常に応答しない場合、Worker が終了し、再起動される可能性があることを意味します。

非同期 Worker の場合、これは 60 秒以内に完了する必要がある単一の HTTP リクエストと同等ではありません。

graceful_timeout:

--graceful-timeout 30

グレースフル リスタートまたはシャットダウン コマンドを受信した後、Worker が既存の作業を完了するまでに許容される待ち時間を示します。

指定時間を過ぎても終了しないWorkerは強制終了される場合があります。

max_requests

--max-requests 1000

一定数のリクエストを処理した後、Worker が自動的に再起動することを示します。

主に潜在的なメモリ リークの影響を軽減するために使用されます。

Recommended combination:

--max-requests-jitter 100

複数の Worker が同じような時間に同時に再起動するのを防ぎます。

注: これはオプションの防御手段であり、すべてのアプリに必要なわけではなく、実際のメモリ リークの修正に代わるものではありません。

8. Workerの数量と性能

Gunicorn は複数のプロセスを利用して、マルチコア CPU の使用率を向上させることができます。

CPU Core 1 ← Worker 1
CPU Core 2 ← Worker 2
CPU Core 3 ← Worker 3
CPU Core 4 ← Worker 4

しかし、これは単なる指標です。実際のプロセスはオペレーティング システムによってスケジュールされ、CPU Core に永続的にバインドされません。

Worker量の影響

Worker を追加します。

  • より多くの CPU リソースを利用できます。
  • プロセスレベルの同時実行機能を向上させることができます。
  • メモリ消費量の増加。
  • データベース接続の数を増やす可能性があります。
  • プロセスのスケジューリングコストが増加する可能性があります。

Worker 多ければ多いほど良いです。

実際のニーズは以下に基づいています。

CPU
RAM
平均リクエスト時間
同期する / 非同期比率
データベース接続数
外部 I/O
リクエストの同時実行性

調整を行います。

Worker がデータベースに接続します

複数の Worker には、独立したインプロセス状態とデータベース接続管理メカニズムがあります。

Worker 1 → Database Connections
Worker 2 → Database Connections
Worker 3 → Database Connections
Worker 4 → Database Connections

次の点に注意する必要があります。

  • Django は、デフォルトでは一般的なインプロセス データベース接続プールを提供しません。
  • データベース接続の作成、終了、再利用は、Django 構成と使用するデータベース ドライバーの影響を受けます。
  • マルチプロセスの展開により、データベース接続の最大数に対する圧力が増加する可能性があります。
  • 追加のスレッド、バックグラウンド タスク、データベース接続プールも接続の合計数に影響します。

Django 非同期モードの場合は、永続接続の構成と外部接続プールの使用に特別な注意を払う必要があります。

9. Nginx + Gunicorn + Uvicorn

一般的な導入アーキテクチャ:

Internet
   ↓
Cloudflare(オプション)
   ↓
Nginx
   │
   ├── HTTPS / TLS
   ├── Static Assets
   ├── Reverse Proxy
   ├── gzip / Brotli
   └── Cache-Control
   ↓
Gunicorn Master
   ↓
Uvicorn Workers
   ↓
Django ASGI
   ↓
PostgreSQL

Nginx の例

server {
    listen 80;

    location / {
        proxy_pass http://backend:8000;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
    }
}

ここでは、Docker Compose内のサービス名をbackendとする。

HTTPS can be processed by another Nginx Server Block.

WebSocket エージェントが必要な場合は、関連する Upgrade および Connection Header を正しく構成する必要もあります。具体的な書き込み方法はNginxのバージョンや展開方法によって異なります。

Proxy Header and security

元のリクエストのプロトコル Host とクライアント IP を正しく識別するには、Uvicorn と Django の両方が必要です。

ただし、クライアントが提供するものを無条件に信頼することはできません。

X-Forwarded-For
X-Forwarded-Proto
Forwarded

これらの Header は、信頼できるリバース プロキシによって設定され、信頼できるプロキシに適切にスコープ設定される必要があります。

そうしないと、IP の偽造やクライアント側での HTTPS の誤判定などの問題が発生する可能性があります。

10. Docker Compose deployment

Dependencies can be installed in Django Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD [
  "gunicorn",
  "config.asgi:application",
  "-k",
  "uvicorn_worker.UvicornWorker",
  "--workers",
  "2",
  "--bind",
  "0.0.0.0:8000",
  "--access-logfile",
  "-",
  "--error-logfile",
  "-"
]

Need to ensure that requirements.txt contains:

Django
gunicorn
uvicorn
uvicorn-worker

およびプロジェクトで実際に使用されるその他の依存関係。

Compose の例

services:
  backend:
    build: ./backend
    expose:
      - "8000"
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - backend

ここでは、コンテナ間のリクエスト転送に関連する構成のみを示します。

実際のプロジェクトでは次の構成も必要です。

  • environment variables.
  • database.
  • Volume。
  • Nginx configuration file.
  • TLS certificate.
  • Health Check。
  • Migration execution process.

Logs in Docker

アクセスログやエラーログはstdout/stderrに書き出すことを推奨します。

Gunicorn:

--access-logfile -
--error-logfile -

In this way, Docker can collect logs directly:

docker compose logs -f backend

コンテナ化された展開の場合、通常、アプリケーションが複雑なローカル ログ ファイルのローテーション メカニズムを維持する必要はありません。

11. Gunicorn + Uvicorn および直接 Uvicorn

Gunicorn + Uvicorn

Container
    ↓
Gunicorn Master
    ↓
Multiple Uvicorn Workers
    ↓
Django

利点:

  • 成熟したプロセス管理。
  • Run multiple processes.
  • Worker automatically restarts.
  • 正常な再起動と信号管理。
  • 豊富な Worker ライフサイクル パラメーター。

短所:

  • さらに多くのプロセスレベルがあります。
  • 構成は比較的複雑です。
  • Gunicorn と Uvicorn Worker 関連の依存関係を同時に維持する必要があります。
  • Worker プロセスの数とリソースの制限に注意する必要があります。

ダイレクト Uvicorn

Container
    ↓
Uvicorn
    ↓
Django

開始:

uvicorn config.asgi:application \
    --host 0.0.0.0 \
    --port 8000

利点:

  • シンプルな構造。
  • 構成が少なくなります。
  • プロセス管理の抽象化レイヤーが 1 つ減ります。
  • コンテナプラットフォームによるプロセスの再起動や水平展開に適しています。

短所:

  • 一部のプロセス管理機能は Gunicorn ほど豊富ではありません。
  • Worker を 1 つだけ実行する場合は、1 つのプロセスの実行機能しか利用できません。

However, Uvicorn also supports:

uvicorn config.asgi:application --workers 4

したがって、Uvicorn を直接使用すると単一のプロセスしか実行できないと単純に考えることはできません。

12. Docker / Kubernetes deployment strategy

単体 VPS+Docker Compose

VPS
 ↓
Docker Compose
 ↓
Gunicorn Master
 ↓
2–4 Uvicorn Workers
 ↓
Django

1 つのコンテナーで複数のプロセスを管理するのに適しています。

スタンドアロン サービスの場合、Gunicorn + Uvicorn が合理的なソリューションです。

Kubernetes

Kubernetes は、複数の Pod を通じて水平方向の拡張を実現できます。

Load Balancer
      ↓
Kubernetes Service
      │
      ├── Pod 1 → Uvicorn
      ├── Pod 2 → Uvicorn
      ├── Pod 3 → Uvicorn
      └── Pod 4 → Uvicorn

Kubernetes is mainly responsible for:

  • Podスケジュール。
  • コンテナーのヘルスチェック。
  • 失敗後に Pod を再作成します。
  • 負荷分散。
  • 水平方向の拡張。

したがって、Kubernetes では、Pod ごとに Uvicorn プロセスを 1 つ使用し、Pod の数を増やして容量を拡張することを検討できます。

ただし、Kubernetes では、各 Pod が 1 つの Worker のみを実行できる必要はありません。

実際の選択には、総合的な考慮が必要です。

  • Pod リソース制限。
  • Application startup time.
  • データベース接続の数。
  • メモリの使用量。
  • Automatic expansion strategy.
  • トラフィックと障害の回復の必要性。

13. Gunicorn よくある質問

Q1: Gunicorn と Uvicorn は一緒に使用する必要がありますか?

必須ではありません。

以下を選択できます。

Gunicorn + WSGI
Uvicorn + ASGI
Gunicorn + Uvicorn Worker + ASGI

フレームワーク、プロトコル、展開のニーズによって異なります。

Q2: ASGI は WSGI よりも必ずしも高速ですか?

不確かな。

ASGI は、同時に I/O を待機するシナリオが多い場合には、より有利である可能性があります。

ただし、主な業務が同期 Django ORM、同期 DRF View、または CPU の集中処理である場合、ASGI に切り替えてもパフォーマンスの向上は保証されません。

実際の負荷テストを通じて判断する必要があります。

Q3: Gunicorn を使用して真のマルチコア並列処理を実現できますか?

これは、複数の Worker プロセスを通じて実現できます。

ただし、Worker が複数あると、メモリとデータベース接続のオーバーヘッドが増加します。

Q4: Worker の数は CPU のコア数の 2 倍に設定する必要がありますか?

固定された公式を機械的に適用すべきではありません。

Worker の数は、実際のリクエスト時間、メモリ、CPU、I/O の比率、データベース ストレス テストと組み合わせる必要があります。

Q5: Celery を使用する必要がありますか?

Gunicorn と Uvicorn は主に Web リクエストを処理します。

Celery などのタスク キューは、HTTP リクエストをブロックする必要のないバックグラウンド タスクを実行するために使用されます。

たとえば:

Client
   ↓
Django API
   ↓
Celery Queue
   ↓
Celery Worker
   ↓
Image Processing / Long-running Job

したがって、Gunicorn Worker は Celery Worker ではありません。

時間のかかる作業の場合、Gunicorn Workerの数を増やすだけでは解決できません。

14. 導入計画の選択

シーン一般的な選択肢
従来の同期 Django アプリケーションGunicorn + WSGI
Django ASGIアプリケーションUvicorn または Gunicorn + Uvicorn
FastAPIUvicorn または Gunicorn + Uvicorn
単体 VPS+Docker ComposeGunicorn + Uvicorn は非常にリーズナブルです
AWS ECS / 普通コンテナサービスどちらの方法も利用可能です
Kubernetes単一プロセス以下の Worker + 以上の Pod を使用できます
小さな個人プロジェクトDirect Uvicorn is simpler
A large number of asynchronous I/OASGI + 真の非同期処理
WebSocketASGI Server + Applications that support WebSocket
Normal synchronization DRF APIGunicorn + WSGI もニーズを満たすことができます

概要

Gunicorn と Uvicorn はそれぞれ、異なるレベルで問題を解決します。

コンポーネント中核的な責任
NginxReverse proxy, HTTPS, static resources
GunicornWorker Process management and life cycle
UvicornASGIプロトコル、HTTP処理、非同期イベントループ
Django / FastAPIAPI, business logic, database access
CeleryBackground asynchronous task processing
Dockerコンテナの操作は環境から隔離されています
Kubernetesコンテナオーケストレーションとスケールアウト

The most critical understanding is:

Gunicorn はプロセス管理の問題を解決し、Uvicorn は ASGI サービス実行の問題を解決します。アプリケーション自体に本当に非同期の利点があるかどうかは、ビジネス コードとその依存関係によって異なります。

単一の VPS 上の Django + DRF プロジェクトの場合は、引き続き Gunicorn + Uvicorn Worker を使用できます。

On this basis, priority should be given to:

  • Worker quantity and memory usage.
  • データベース接続の数。
  • Request timeouts and logs.
  • Nginx reverse proxy configuration.
  • Health checks and automatic restarts.
  • Is Celery required for long running tasks.

参考資料