重い処理をすると「[error] 3896#0: *1 upstream prematurely closed connection while reading response header from upstream,」というエラーが出たので、考えられる解決策を紹介します。
実行環境は以下の通りです。
- aws ec2 (t3.small)
- nginx
- django
- gunicorn
- mysql
- load balancer
エラーが起こる原因
[error] 3896#0: *1 upstream prematurely closed connection while reading response header from upstream
というエラーは、主に Nginx が upstream(Gunicorn)からのレスポンスを受け取る前に接続が切断された 場合に発生します。これは、処理が重いために タイムアウト や リソース不足 などが原因で起こることが多いです。
【解決策1】Nginx のタイムアウト設定を延長する
Nginx のデフォルトの proxy_read_timeout
は 60 秒程度ですが、処理が重い場合はこれを延長することで解決する可能性があります。
server {
location / {
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
}
}
設定変更後、Nginx を再起動してください。
sudo systemctl restart nginx
【解決策2】Gunicorn のタイムアウトを延長する
Gunicorn のデフォルトのタイムアウトは 30 秒です。これを長めに設定します。
gunicorn
の起動オプションに --timeout 300
を追加します。
gunicorn --timeout 300 --workers 3 myproject.wsgi:application
または、gunicorn.service
(systemd) に設定を追加:
[Service]
ExecStart=/path/to/venv/bin/gunicorn --timeout 300 --workers 3 myproject.wsgi:application
設定変更後、Gunicorn を再起動してください。
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
【解決策3】Gunicorn のワーカー数を調整する
現在の t3.small
(2vCPU, 2GB RAM) では、Gunicorn の ワーカー数が多すぎるとメモリ不足 になります。
適切なワーカー数の目安は:
ワーカー数 = (CPU コア数 × 2) + 1
t3.small
(2 vCPU) なら 5ワーカーまで が適切です。
gunicorn --workers 5 myproject.wsgi:application
注意:
ワーカー数を増やしすぎると、逆に OOM (Out of Memory) でプロセスが落ちるため、慎重に設定してください。
【解決策4】Gunicorn を sync
から gevent
に変更
Gunicorn のデフォルトの sync
ワーカー はリクエストごとにブロックされるため、処理が遅くなることがあります。gevent
を使うと 非同期処理 になり、パフォーマンスが改善する可能性があります。
pip install gunicorn gevent
gunicorn --worker-class gevent --workers 3 myproject.wsgi:application
【解決策5】Django のデータベースクエリを最適化する
重い処理の原因が データベースの負荷 の場合、以下を試してください。
- クエリの最適化 (
select_related
,prefetch_related
) - インデックスの追加 (
EXPLAIN ANALYZE
でボトルネックを特定) - MySQL の設定調整 (
innodb_buffer_pool_size
の増加) - Redis キャッシュの導入 (
django-cacheops
やdjango-redis
)
【解決策6】AWS Load Balancer のタイムアウトを延長する
AWS の ALB/NLB のデフォルトのタイムアウトは 60 秒 です。
長時間処理が必要な場合は、 タイムアウトを 300 秒程度に設定 してください。
変更方法
AWS コンソール → EC2 → Load Balancer → 対象の ALB/NLB を選択
→ 属性 → アイドルタイム
を 300
に変更。
【解決策7】EC2 インスタンスタイプのアップグレード
t3.small (2vCPU, 2GB RAM)
は負荷が高いとリソース不足になりやすいです。
アップグレードの選択肢
インスタンス | vCPU | RAM | 用途 |
---|---|---|---|
t3.small | 2 | 2GB | 現在の環境 |
t3.medium | 2 | 4GB | メモリ増加 |
t3.large | 2 | 8GB | さらに余裕 |
EC2 のリソースが不足していないか、以下のコマンドで確認してください。
top
free -m
df -h
CPU やメモリ使用率が高い場合、t3.medium
以上へアップグレードを検討してください。
【解決策8】ログの確認(エラーの詳細を特定)
どこでタイムアウトが発生しているか特定するために、以下のログを確認してください。
sudo tail -f /var/log/nginx/error.log
sudo journalctl -u gunicorn --no-pager | tail -n 50
sudo tail -f /var/log/mysql/error.log
まとめ
優先度 | 対策 |
---|---|
🔥 最優先 | ① Nginx の proxy_read_timeout を増やす |
✅ 優先 | ② Gunicorn の timeout を増やす |
✅ 優先 | ③ Gunicorn の workers 数を適正化 |
🛠 次善策 | ④ Gunicorn を gevent に変更 |
🛠 次善策 | ⑤ Django のデータベースクエリを最適化 |
🔄 環境調整 | ⑥ AWS Load Balancer のタイムアウトを延長 |
🔄 環境調整 | ⑦ EC2 インスタンスのアップグレード |
まずは Nginx・Gunicorn のタイムアウト設定を増やす ところから試し、ログを確認しながら対処していくと良いでしょう。
コメント