uWSGI

高性能で多機能なPython WSGI/HTTPサーバー。120以上のパラメータで詳細設定可能。HTTPS対応、専用uwsgiプロトコル、spooler機能付き。

アプリケーションサーバーPythonWSGIHTTPサーバー高性能エンタープライズアプリケーションサーバー

アプリケーションサーバー

uWSGI

概要

uWSGIは、高性能で多機能なPython WSGI/HTTPサーバーです。120以上のパラメータで詳細設定が可能で、HTTPS対応、専用uwsgiプロトコル、spooler機能を備えています。高性能を求めるPythonアプリケーションで採用され、現在はメンテナンスモードですが、高パフォーマンスが必要な場合に選択されています。ベンチマークでGunicornより高性能を発揮します。

詳細

uWSGIは2009年にUnbit社によって開発され、Python、Ruby、Perl、Luaなど多言語対応のアプリケーションサーバーとして設計されました。特にPython環境では、WSGI準拠の高性能サーバーとして多くのエンタープライズ環境で採用されています。nginxとの連携において専用のuwsgiプロトコルを使用することで、HTTPよりも高いパフォーマンスを実現できます。

主要な技術的特徴

  • 高性能: マルチプロセス・マルチスレッド対応
  • 多機能: キャッシュ、セッション管理、スケジューリング
  • 専用プロトコル: nginxとの高速連携uwsgiプロトコル
  • 豊富な設定オプション: 120以上の詳細設定パラメータ
  • 内蔵機能: 静的ファイル配信、ロードバランシング
  • 多言語対応: Python以外の言語もサポート

用途

  • 高負荷Pythonアプリケーション
  • エンタープライズWebアプリケーション
  • Django、Flask本番環境
  • マイクロサービス高性能基盤
  • リアルタイムアプリケーション
  • レガシーアプリケーション高性能化

メリット・デメリット

メリット

  • 高性能: Gunicornを上回るベンチマーク結果
  • 豊富な機能: オールインワンソリューション
  • 詳細設定: きめ細かいチューニングが可能
  • nginx連携: 専用プロトコルによる高速通信
  • 内蔵機能: キャッシュ、セッション、静的ファイル配信
  • 実績: 多くのエンタープライズ環境での採用実績

デメリット

  • 複雑性: 設定が複雑で学習コストが高い
  • メンテナンスモード: 新機能開発が停止
  • ドキュメント: Gunicornと比較して情報が少ない
  • デバッグ困難: 問題の特定が難しい場合がある
  • リソース使用量: 機能が多い分、メモリ使用量が多い

インストール・基本設定

前提条件

# Python バージョン確認
python --version
python3 --version

# 開発ツールの確認
gcc --version
make --version

# Python開発ヘッダー
# Ubuntu/Debian
sudo apt-get install python3-dev

# CentOS/RHEL
sudo yum install python3-devel

インストール方法

pip インストール

# 基本インストール
pip install uwsgi

# 特定のバージョン
pip install uwsgi==2.0.21

# 開発ライブラリ付きインストール
pip install --no-binary uwsgi uwsgi

ソースコンパイル

# 依存関係のインストール
# Ubuntu/Debian
sudo apt-get install build-essential python3-dev libssl-dev libpcre3-dev

# CentOS/RHEL
sudo yum groupinstall "Development Tools"
sudo yum install python3-devel openssl-devel pcre-devel

# uWSGI ソースダウンロードとコンパイル
wget https://projects.unbit.it/downloads/uwsgi-latest.tar.gz
tar -xzf uwsgi-latest.tar.gz
cd uwsgi-*
make

パッケージマネージャー

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install uwsgi uwsgi-plugin-python3

# CentOS/RHEL (EPEL必要)
sudo yum install epel-release
sudo yum install uwsgi uwsgi-plugin-python36

基本的なアプリケーション起動

最小限のWSGIアプリケーション

# app.py
def application(environ, start_response):
    """基本的なWSGIアプリケーション"""
    status = '200 OK'
    headers = [('Content-type', 'text/plain')]
    start_response(status, headers)
    return [b'Hello from uWSGI!']

Flaskアプリケーション例

# flask_app.py
from flask import Flask, jsonify
import os

app = Flask(__name__)

@app.route('/')
def hello():
    return jsonify({
        'message': 'Hello from uWSGI!',
        'worker_id': os.getpid()
    })

@app.route('/health')
def health():
    return jsonify({'status': 'healthy'}), 200

@app.route('/info')
def info():
    return jsonify({
        'uwsgi_version': os.environ.get('UWSGI_VERSION', 'unknown'),
        'worker_id': os.getpid(),
        'python_version': os.sys.version
    })

if __name__ == '__main__':
    app.run(debug=True)

基本起動コマンド

# 最も基本的な起動
uwsgi --http :8000 --wsgi-file app.py

# Flask アプリケーション
uwsgi --http :8000 --module flask_app:app

# より実用的な設定
uwsgi --http :8000 --module flask_app:app --processes 4 --threads 2 --master

設定とカスタマイズ

INI設定ファイル

; uwsgi.ini
[uwsgi]
; アプリケーション設定
module = flask_app:app
callable = app

; サーバー設定
http = :8000
; socket = /tmp/uwsgi.sock
processes = 4
threads = 2
master = true

; パフォーマンス設定
max-requests = 1000
max-requests-delta = 100
harakiri = 30
harakiri-verbose = true
buffer-size = 32768

; ロギング
logto = /var/log/uwsgi/app.log
log-maxsize = 50000000
log-backupcount = 5
disable-logging = false

; プロセス管理
pidfile = /var/run/uwsgi.pid
daemonize = /var/log/uwsgi/daemon.log
uid = www-data
gid = www-data

; 再読み込み設定
touch-reload = /tmp/reload.me
py-autoreload = 1

; 統計情報
stats = 127.0.0.1:9191
stats-http = true

; メモリ制限
reload-on-as = 512
reload-on-rss = 256
limit-as = 1024

; 自動スケーリング
cheaper = 1
cheaper-initial = 2
cheaper-step = 1
cheaper-algo = busyness
cheaper-overload = 5

JSON設定ファイル

{
  "uwsgi": {
    "module": "flask_app:app",
    "master": true,
    "processes": 4,
    "socket": "/tmp/uwsgi.sock",
    "chmod-socket": 666,
    "vacuum": true,
    "die-on-term": true,
    "max-requests": 1000,
    "harakiri": 30,
    "stats": "127.0.0.1:9191"
  }
}

YAML設定ファイル

# uwsgi.yml
uwsgi:
  module: flask_app:app
  master: true
  processes: 4
  threads: 2
  socket: /tmp/uwsgi.sock
  chmod-socket: 666
  vacuum: true
  die-on-term: true
  
  # パフォーマンス
  max-requests: 1000
  harakiri: 30
  buffer-size: 32768
  
  # ログ
  logto: /var/log/uwsgi/app.log
  
  # 統計
  stats: 127.0.0.1:9191
  stats-http: true

環境別設定

; development.ini
[uwsgi]
module = flask_app:app
http = :8000
master = true
processes = 2
threads = 2
py-autoreload = 1
honour-stdin = true

; production.ini
[uwsgi]
module = flask_app:app
socket = /var/run/uwsgi.sock
chmod-socket = 666
master = true
processes = 8
threads = 4
vacuum = true
die-on-term = true
max-requests = 5000
harakiri = 60
daemonize = /var/log/uwsgi/app.log
pidfile = /var/run/uwsgi.pid
uid = www-data
gid = www-data

高度な機能と最適化

内蔵キャッシュ設定

[uwsgi]
; キャッシュ設定
cache2 = name=mycache,items=1000,blocksize=1024
; cache2 = name=sessions,items=10000,blocksize=64

; Pythonアプリケーションでのキャッシュ使用例
; import uwsgi
; uwsgi.cache_set("key", "value", 0, "mycache")
; value = uwsgi.cache_get("key", "mycache")

静的ファイル配信

[uwsgi]
module = flask_app:app
master = true
processes = 4

; 静的ファイル配信
static-map = /static=/var/www/static
static-map = /media=/var/www/media
static-expires-type = text/css=3600
static-expires-type = application/javascript=3600
static-expires-type = image/png=86400

; ファイル監視
check-static = /var/www/static

ロードバランシング

[uwsgi]
; マスターフィードバック
master-fifo = /tmp/uwsgi-fifo

; ワーカーリサイクル
max-requests = 1000
max-requests-delta = 100
reload-on-as = 512
reload-on-rss = 256

; 自動スケーリング
cheaper = 2
cheaper-initial = 4
cheaper-step = 1
cheaper-algo = busyness
cheaper-overload = 10
cheaper-busyness-multiplier = 30
cheaper-busyness-min = 20
cheaper-busyness-max = 70
cheaper-busyness-backlog-alert = 16
cheaper-busyness-backlog-step = 2

セッション管理

[uwsgi]
; セッションキャッシュ
cache2 = name=sessions,items=10000,blocksize=64,store=/tmp/sessions.cache

; セッション設定
session-storage = cache:sessions
session-cookie-name = uwsgi_session
session-cookie-domain = .example.com
session-cookie-secure = true
session-cookie-httponly = true

Spooler機能(非同期タスク)

[uwsgi]
; スプーラー設定
spooler = /var/spool/uwsgi
spooler-processes = 2
spooler-frequency = 5

; Pythonでの使用例
# spooler_tasks.py
import uwsgi

def send_email(arguments):
    """非同期メール送信タスク"""
    email = arguments.get(b'email', b'').decode()
    subject = arguments.get(b'subject', b'').decode()
    
    # メール送信ロジック
    print(f"Sending email to {email} with subject: {subject}")
    
    return uwsgi.SPOOL_OK

# タスクのスケジューリング
uwsgi.spool({
    b'email': b'[email protected]',
    b'subject': b'Hello from uWSGI Spooler'
})

nginx連携とプロトコル最適化

nginx uwsgi_pass設定

# /etc/nginx/sites-available/myapp
upstream django {
    server unix:///var/run/uwsgi.sock;
}

server {
    listen 80;
    server_name example.com;
    charset utf-8;

    # ファイルアップロード設定
    client_max_body_size 75M;

    # Django media
    location /media {
        alias /var/www/media;
        expires 1y;
        add_header Cache-Control "public";
    }

    # Django static
    location /static {
        alias /var/www/static;
        expires 1y;
        add_header Cache-Control "public";
    }

    # Django アプリケーション
    location / {
        uwsgi_pass django;
        include /etc/nginx/uwsgi_params;
        
        # uWSGI プロトコル最適化
        uwsgi_read_timeout 300;
        uwsgi_send_timeout 300;
        uwsgi_connect_timeout 300;
        uwsgi_buffers 32 32k;
        uwsgi_buffer_size 32k;
        uwsgi_busy_buffers_size 64k;
        
        # リクエストヘッダー
        uwsgi_param REMOTE_ADDR $remote_addr;
        uwsgi_param REMOTE_USER $remote_user;
        uwsgi_param REQUEST_METHOD $request_method;
        uwsgi_param REQUEST_URI $request_uri;
        uwsgi_param QUERY_STRING $query_string;
        uwsgi_param CONTENT_TYPE $content_type;
        uwsgi_param CONTENT_LENGTH $content_length;
        uwsgi_param SERVER_NAME $server_name;
        uwsgi_param SERVER_PORT $server_port;
        uwsgi_param SERVER_PROTOCOL $server_protocol;
    }
}

uwsgi_params設定

# /etc/nginx/uwsgi_params
uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

パフォーマンス最適化

マルチプロセス・マルチスレッド最適化

[uwsgi]
; CPU最適化
processes = 8
threads = 4
enable-threads = true
thread-stacksize = 512

; メモリ最適化
buffer-size = 32768
post-buffering = 8192
upload-progress = /tmp/upload_progress

; I/O最適化
async = 1000
ugreen = true

; プロセス最適化
lazy-apps = true
preforking = true

システムレベル最適化

# /etc/security/limits.conf
www-data soft nofile 65535
www-data hard nofile 65535
www-data soft nproc 32768
www-data hard nproc 32768

# /etc/sysctl.conf
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 5000
vm.overcommit_memory = 1

メモリとCPU監視

[uwsgi]
; メモリ監視
memory-report = true
reload-on-as = 1024
reload-on-rss = 512
limit-as = 2048

; CPU監視
cpu-affinity = 1,2,3,4
cpu-affinity-ignore-worker = 0

; プロファイリング
profiler = true
profile-dump = /tmp/uwsgi.profile

本番環境設定

Systemd サービス設定

# /etc/systemd/system/uwsgi.service
[Unit]
Description=uWSGI Emperor service
After=network.target

[Service]
Type=forking
User=www-data
Group=www-data
ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Restart=always
KillSignal=SIGQUIT
StandardError=syslog
NotifyAccess=all
RuntimeDirectory=uwsgi
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target

Emperor設定

; /etc/uwsgi/emperor.ini
[uwsgi]
emperor = /etc/uwsgi/sites
uid = www-data
gid = www-data
pidfile = /var/run/uwsgi-emperor.pid
daemonize = /var/log/uwsgi/emperor.log
emperor-stats = 127.0.0.1:9192
emperor-stats-server = 127.0.0.1:9193

Docker設定

# Dockerfile
FROM python:3.11-slim

# システム依存関係
RUN apt-get update && apt-get install -y \
    gcc \
    g++ \
    make \
    libssl-dev \
    libpcre3-dev \
    python3-dev \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Python依存関係
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install uwsgi

# アプリケーションコピー
COPY . .

# 設定ファイル
COPY uwsgi.ini /app/

# ログディレクトリ
RUN mkdir -p /var/log/uwsgi && \
    chown -R www-data:www-data /var/log/uwsgi

# 非rootユーザー
RUN useradd --create-home --shell /bin/bash www-data || true
USER www-data

EXPOSE 8000

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1

CMD ["uwsgi", "--ini", "uwsgi.ini"]

監視・ログ・運用

統計情報とモニタリング

# 統計情報取得
curl http://127.0.0.1:9191

# JSON形式
curl http://127.0.0.1:9191 | python -m json.tool

# 特定の統計
curl http://127.0.0.1:9191/workers

# uWSGI top(リアルタイム監視)
pip install uwsgitop
uwsgitop 127.0.0.1:9191

ログローテーション

# /etc/logrotate.d/uwsgi
/var/log/uwsgi/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    postrotate
        /bin/kill -USR1 $(cat /var/run/uwsgi.pid) > /dev/null 2>&1 || true
    endscript
}

動的設定変更

# ワーカー数変更
echo "set_var:processes=8" > /tmp/uwsgi-fifo

# ログレベル変更
echo "set_var:log-level=debug" > /tmp/uwsgi-fifo

# 統計情報リセット
echo "reset_stats" > /tmp/uwsgi-fifo

# メモリ情報
echo "dump_memory" > /tmp/uwsgi-fifo

バックアップとリストア

#!/bin/bash
# backup-uwsgi.sh

BACKUP_DIR="/backup/uwsgi"
DATE=$(date +%Y%m%d_%H%M%S)

# 設定ファイルバックアップ
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/uwsgi_config_$DATE.tar.gz \
    /etc/uwsgi \
    /var/log/uwsgi

# アプリケーションバックアップ
tar -czf $BACKUP_DIR/uwsgi_app_$DATE.tar.gz \
    /var/www/myapp

echo "Backup completed: $DATE"

トラブルシューティング

一般的な問題と解決策

# プロセス確認
ps aux | grep uwsgi

# ソケットファイル権限確認
ls -la /var/run/uwsgi.sock

# ログ確認
tail -f /var/log/uwsgi/app.log

# 設定テスト
uwsgi --ini uwsgi.ini --check-static

# メモリ使用量確認
uwsgi --show-config

# デバッグモード起動
uwsgi --ini uwsgi.ini --honour-stdin

パフォーマンス分析

# performance_test.py
import uwsgi
import time

def application(environ, start_response):
    start_time = time.time()
    
    # アプリケーション処理
    status = '200 OK'
    headers = [('Content-type', 'text/plain')]
    start_response(status, headers)
    
    # パフォーマンスログ
    process_time = time.time() - start_time
    uwsgi.log(f"Request processed in {process_time:.4f}s")
    
    return [f'Request processed in {process_time:.4f}s'.encode()]

参考ページ