いつも忘れるので、nginxの自分用のメモを残します。
Nginxの設定の参考資料はnginx実践ガイド。
動作の確認のため、負荷テストツールで負荷をかけてみてみます。ツールはJMeterを使用します。
環境は、コンテナでたてます。
Nginxの構造
Nginxは、Webサーバやロードバランサー、リバースプロキシサーバとして使うことができるOSSです。
Nginxはイベント駆動モデルと呼ばれるアーキテクチャで、HTTPリクエストを1プロセス1スレッドで処理しています。
masterプロセスとworkerプロセスがあり、masterプロセスは、設定ファイルの読み込み、ネットワークの通信に使うソケットの待ち受けを設定し、workerの起動と監視を行います。
workerプロセスは、ネットワーク処理のイベントループを処理し、masterが設定したソケットを使って接続を受け付け、ネットワークやファイルI/Oを実施します。HTTPやSSL/TLSのプロトコル処理もworkerの仕事です。
workerは内部で非同期I/Oの多重化、ノンブロッキングI/Oの多重化をしており、1つのプロセスで複数のリクエストを並行して処理できるようになっています。一方でファイルI/Oはデフォルトでは多重化しないようで、ファイルI/Oがボトルネックになることがあるようです。ここら編は設定で変えることができるようです。
最近、Webサーバのシェア率でApacheを抜いたそうですね。
準備
Nginxコンテナの設定
version: "3.9"
services:
web:
image: nginx:latest
container_name: my-webapp
volumes:
- ./web/nginx.conf:/etc/nginx/nginx.conf
- ./web/my-webapp.conf:/etc/nginx/conf.d/my-webapp.conf
- ./web/html:/usr/share/nginx/html
ports:
- 8081:8080
deploy:
resources:
limits:
cpus: '1'
memory: 1G
コンテナはCPU1コア、メモリ1Gで設定します。
・ログ
サーバの内部統計情報を出すため、下記の設定をします。
server {
listen 8080 default_server;
location /stub_status {
stub_status;
access_log off;
allow 127.0.0.1;
deny all;
}
}
これをして、/stub_statusにアクセスすると
接続情報などが見れます。
レスポンスにかかった時刻は、
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" $request_time';
access_log /dev/stdout main;
}
なお、Apache JMeterは他者様の記事を参考に設定します。
ここまでが計測のための準備。
workerの設定
いくつか設定値はありますが、重要なのは下記
worker_processes:workerのプロセス数、基本的にCPUのコア数
worker_connections:1つのworkerの最大接続数、1コネクションが1接続を担当
worker_rlimit_nofile:1つのworkerのファイルディスクリプタ の上限値
ファイルディスクリプタとは、ファイルを識別をする目印で、OSで限界値が設定されています。/proc/sys/fs/file-max
などに書かれていて、この限界値を超えるとエラーになります。
そのため、設定値的には
ファイルディスクリプタの限界値 > worker_processes×worker_rlimit_nofile
となります。1プロセスで、worker_connections数の接続があるため、
実際は、
ファイルディスクリプタの限界値 > worker_processes×worker_rlimit_nofile
worker_rlimit_nofile > worker_connections×接続されて使うファイルディスクリプタ数
となります。
他者様の記事によると、ソケットファイルやコンテンツファイル、バックエンド側で使うものなどを踏まえて、3~4倍がいいらしいですが、余裕を持ってもっと大きくてもよさそうです。
また、同時に接続できる数は
同時に接続できる数 = worker_processes×worker_connections
になります。
ファイルディスクリプタの限界値からworker_connection数の限界値はわかりましたが、CPUやメモリは一応どんな感じかも考えます。
ルートパスにきたリクエストにたいして、HTMLだけを返すように設定して、
# Nginxコンテナ
resources:
limits:
cpus: '0.10'
memory: 1G
# Nginx
worker_connections:2048
worker_processes:1
# ApacheJMeter
スレッド数:15000
Ramp-Up期間(秒):1
ループ回数:1
とした時、CPU使用率が10%(コンテナの限界値)になり、いくつかのリクエストが失敗していました。
これは
・CPU使用率が100%
→workerが限界まで動いた(worker_connectionsの分でリクエストを処理したら100%使った)
・いくつかのリクエストが失敗
→リクエストをさばけるキャパがなかった(worker_connectionsが足りない)
ということになるかと思います。
この場合、
対応できなかったリクエストに対応するためにworker_connectionを増やしても、CPU使用率が100%で処理が間に合わないので、単純にサーバの処理能力不足といえます。別サーバなどでNginxサーバを立てて負荷を分散する必要があります。
逆に、CPU使用率がそこまで高くなっていないのにリクエストが失敗していれば、サーバの処理は限界ではないのに、worker_connectionが足りないということが言えるかと思います。メモリ不足も同じで、サーバの処理能力的に不足しているということになるかと思います。
ただ、これはNginxだけを使った場合の話で、実際は後ろでアプリケーションが動き、同じサーバの場合はそちらのメモリ使用量やCPU使用率も考慮する必要があります。
このあたりは実際のアプリケーションで、負荷テストを行い、どのくらいのリクエストがさばけるのか確認する必要があります。
まとめると、
同時にさばけるリクエスト数を上げる
→worker_connectionsを高くする
CPU使用率やメモリ使用量が限界値をこえている
→別サーバなどでnginxサーバをたてて負荷分散する(+worker_connectionsも高すぎる疑惑)
CPU使用率やメモリ使用量がそこまで高くなっていないのにリクエストが失敗している
→worker_connectionsが低い