uWSGI
高性能で多機能なPython WSGI/HTTPサーバー。120以上のパラメータで詳細設定可能。HTTPS対応、専用uwsgiプロトコル、spooler機能付き。
アプリケーションサーバー
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()]