Python ランタイムアーキテクチャ

WSGI/ASGIサーバーとリクエスト処理フロー

アーキテクチャ概要

クライアント
→ HTTP/HTTPS →
リバースプロキシ
Nginx
→ HTTP / Unix Socket →
WSGIサーバー
Gunicorn / uWSGI
Python
インタープリター
Application
Django / Flask / FastAPI

WSGI vs ASGI

WSGI (Web Server Gateway Interface)

  • 同期処理
  • • Django, Flaskで使用
  • • Gunicorn, uWSGI
  • • シンプルで安定

ASGI (Asynchronous SGI)

  • 非同期処理
  • • FastAPI, Starlette, Django 3.0+
  • • Uvicorn, Daphne
  • • WebSocket対応、高並行

データフローと制限ポイント

1
Nginx (リバースプロキシ)
client_max_body_size, proxy_read_timeout
proxy_connect_timeout, proxy_send_timeout
2
Gunicorn / uWSGI
timeout, workers, worker_connections
limit-post (uWSGI)
3
Python / フレームワーク
Django: DATA_UPLOAD_MAX_MEMORY_SIZE, FILE_UPLOAD_MAX_MEMORY_SIZE
Flask: MAX_CONTENT_LENGTH

WSGIサーバー比較

項目GunicornuWSGIUvicorn (ASGI)
プロトコルWSGIWSGI + 独自ASGI
設定の複雑さシンプル複雑(多機能)シンプル
パフォーマンス良好高い非常に高い
非同期対応gevent workerasync modeネイティブ
推奨用途Django, Flask高パフォーマンス要件FastAPI, async処理

Gunicornワーカーモデル

sync (デフォルト)

  • • 同期ワーカー
  • • 1リクエスト/ワーカー
  • • CPU bound処理向け

gevent / eventlet

  • • 非同期ワーカー
  • • 多数の同時接続
  • • I/O bound処理向け

gthread

  • • スレッドワーカー
  • • マルチスレッド処理
  • • GIL制約あり

ワーカー数の目安: (2 × CPUコア数) + 1
例: 4コアCPU → 9 workers

各層の設定詳細

Nginx

1# /etc/nginx/sites-available/app.conf
2upstream app_server {
3 server unix:/run/gunicorn.sock fail_timeout=0;
4 # または server 127.0.0.1:8000;
5}
6
7server {
8 listen 80;
9 server_name example.com;
10
11 client_max_body_size 100M; # リクエストボディ制限
12 client_body_timeout 60s;
13
14 location / {
15 proxy_pass http://app_server;
16 proxy_set_header Host $host;
17 proxy_set_header X-Real-IP $remote_addr;
18 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
19
20 proxy_connect_timeout 60s;
21 proxy_read_timeout 60s; # Gunicornからの応答待ち
22 proxy_send_timeout 60s;
23 }
24
25 location /static/ {
26 alias /var/www/app/static/; # 静的ファイルはNginxから直接
27 }
28}

Gunicorn

1# gunicorn.conf.py
2bind = "unix:/run/gunicorn.sock"
3# または bind = "0.0.0.0:8000"
4
5# ワーカー設定
6workers = 9 # (2 * CPU) + 1
7worker_class = "sync" # sync, gevent, gthread, uvicorn.workers.UvicornWorker
8threads = 1 # gthread用
9
10# タイムアウト
11timeout = 30 # ワーカータイムアウト (秒)
12graceful_timeout = 30 # graceful shutdown待ち
13keepalive = 2 # Keep-Alive接続のタイムアウト
14
15# リクエスト制限
16limit_request_line = 4094 # リクエストライン最大長
17limit_request_fields = 100 # ヘッダー最大数
18limit_request_field_size = 8190
19
20# ロギング
21accesslog = "/var/log/gunicorn/access.log"
22errorlog = "/var/log/gunicorn/error.log"
23loglevel = "info"
24
25# プロセス管理
26max_requests = 1000 # ワーカーリサイクル
27max_requests_jitter = 50 # リサイクルにランダム性追加
28preload_app = True # アプリ事前ロード

Django settings.py

1# settings.py
2# ファイルアップロード制限
3DATA_UPLOAD_MAX_MEMORY_SIZE = 104857600 # 100MB (POSTデータ)
4FILE_UPLOAD_MAX_MEMORY_SIZE = 104857600 # 100MB (ファイル)
5DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000 # フィールド数制限
6
7# 一時ファイル設定
8FILE_UPLOAD_TEMP_DIR = "/tmp"
9FILE_UPLOAD_PERMISSIONS = 0o644
10
11# セキュリティ
12ALLOWED_HOSTS = ["example.com", "www.example.com"]
13CSRF_TRUSTED_ORIGINS = ["https://example.com"]

FastAPI + Uvicorn

1# main.py
2from fastapi import FastAPI, UploadFile
3from fastapi.middleware.cors import CORSMiddleware
4
5app = FastAPI()
6
7# ファイルアップロード
8@app.post("/upload/")
9async def upload_file(file: UploadFile):
10 # file.size でサイズチェック可能
11 contents = await file.read()
12 return {"filename": file.filename, "size": len(contents)}
13
14# 起動コマンド
15# uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 --timeout-keep-alive 30

よくあるエラーと対処

[CRITICAL] WORKER TIMEOUT

原因: Gunicornワーカーがtimeout秒以内に応答しなかった

対処:

  • timeout値を増加
  • 重い処理は非同期タスク(Celery)に移動
  • geventワーカーを検討

502 Bad Gateway

原因: Gunicornがダウン、またはソケット接続失敗

確認箇所:

  • Gunicornプロセスの状態確認
  • ソケットファイルの権限
  • Nginxのupstream設定

MemoryError

原因: ワーカープロセスのメモリ枯渇

対処:

  • max_requests でワーカーを定期リサイクル
  • メモリリークの調査
  • 大きなデータはストリーミング処理

監視項目

Gunicorn

  • • ワーカープロセス数
  • • リクエスト処理時間
  • • メモリ使用量/ワーカー
  • • ワーカーリスタート回数

アプリケーション

  • • リクエスト/秒
  • • エラー率 (4xx/5xx)
  • • データベースクエリ時間
  • • 外部API呼び出し時間

systemd設定例

1# /etc/systemd/system/gunicorn.service
2[Unit]
3Description=Gunicorn daemon for Django
4After=network.target
5
6[Service]
7User=www-data
8Group=www-data
9WorkingDirectory=/var/www/app
10ExecStart=/var/www/app/venv/bin/gunicorn \
11 --config gunicorn.conf.py \
12 myapp.wsgi:application
13ExecReload=/bin/kill -s HUP $MAINPID
14Restart=on-failure
15RestartSec=5
16
17# リソース制限
18MemoryMax=2G
19CPUQuota=200%
20
21[Install]
22WantedBy=multi-user.target