とある大容量ファイルを扱うWebシステムを運用していたところ
サーバーのストレージが枯渇しかけるという局面に出会ったのが今回のお話。
結論を言うとnginxの設定値に問題があったのですが、
原因を見つけるまでの経緯と注意点について備忘録を残しておこうと思います。
ちなみにOSはDebian系、Webサーバーはnginx、アプリケーションはpythonです。
発覚
大容量ファイル(数GB~数十GB)のファイルを扱うWebシステムを運用して、
利用がだいぶ増えていたある日、サーバーの物理ストレージが数GB単位で減っては増え
減っては増えを繰り返していることが分かりました。
はじめはアプリケーションに問題があると考え、
ファイルのアップロード/ダウンロードを行うコードを読み返しましたが
特に直接ストレージに干渉するような処理は見受けられず。
ただ、検証環境でも再現はするのでまずはdf,duコマンドで確認しました。
すると全体のストレージ空き容量と実際に見えるサイズが異なる状態であったので
lsofコマンドでプロセスが開いているファイルを見たところ
$ sudo lsof / | sort -k7 -nr | head -1
nginx ** app ** ** **,* 1055604736 ** /var/lib/nginx/proxy/**** (deleted)
きっちりnginxが1GB使っていることが確認できました。
対処
アプリケーションの作り上、アップロードは数MBのチャンクでデータを扱っていたため
今回GB単位でストレージを消費するのはダウンロードだけでした。
ということで、ドキュメントを読み漁っていたところ原因は
nginxのバッファリングであったということが分かりました。
Module ngx_http_proxy_module>proxy_buffering
NGINX リバースプロキシ>バッファの設定
localhost内でアプリケーションをプロキシしていたので
そのレスポンスをnginxがバッファしていたということになります。
ただし、nginxの一時ファイルは1GBまでの制限があるので、今回は恩恵を受けられない。
ということで該当パターンのみ設定をOFFにしました。
以下、ドキュメントより設定例
location /some/path/ {
proxy_buffering off;
proxy_pass http://localhost:8000;
}
ちなみにバッファがONになっていることでアプリケーション稼働は最適化されるなど
メリットも多いので制限をかけるかどうかは一考の余地があります。
上記設定後、テストしたところストレージを食いつぶすような動きはなくなりました。
余談
今回はダウンロードが主な問題になりましたが、
アプリケーションの作り次第ではアップロードで大容量ファイルを扱う際も
同じ問題にぶつかることがあると思います。
その際は、proxy_request_bufferingを設定してあげればいいようです。