ククログ

株式会社クリアコード > ククログ > サポート事例紹介: nginxの最大接続数とreuseport

サポート事例紹介: nginxの最大接続数とreuseport

こんにちは。データ収集ツールFluentdのメンテナーの福田です。

今回の記事では、有名なWebサーバーアプリケーションであるnginxの最大接続数のチューニングについて調査した事例を紹介します。

最大接続数をチューニングするにあたり、reuseport設定とファイルディスクリプター数上限(worker_rlimit_nofile)を考慮する必要がある、という点が重要です。

この調査はクリアコードのFluentd法人様向けサポートサービスの一貫で実施したもので、 Fluentdとセットで周辺のフリーソフトウェアのサポートを実施した事例となっています。

nginxなどのwebサーバーの性能チューニングや、クリアコードの法人様向けサポートサービスに興味のある方は、ぜひ本記事をご覧ください。

背景

今回のサポート事例は、nginxの限界性能についてお客様からご質問をいただき、最大接続数のチューニングの仕方について調査した、というものになります。

nginxでは、同時に多くの接続が生じると、次のようにworker_connections are not enoughToo many open filesといったエラーが発生します。

[alert] xxxx: *xxxx 1024 worker_connections are not enough while connecting
 to upstream, client: xxxx, server: xxxx, request: "xxxx", upstream: "xxxx", host: "xxxx"
[alert] xxxx: *xxxx socket() failed (24: Too many open files) while
 connecting to upstream, client: xxxx, server: xxxx, request: "xxxx", upstream: "xxxx", host: "xxxx"
[crit] xxxx: accept4() failed (24: Too many open files)

このようなエラーが発生せずに処理できる最大の接続数はどう決まるのか、およびその正しいチューニング方法について、調査しました。

なお、本記事は以下の環境を前提とします。

  • nginx: version 1.16.1
  • OS: RHEL 8.6

基本的な考え方と計算式

今回の事例では、nginxをフォワードプロキシとして利用していました。

検証したところ、およその最大接続数は基本的には次の計算式で求められました。

2で割るのは、1接続あたりプロキシ元とプロキシ先の2つ接続を持つ必要があるからだと推測できます(これは設定によって変わるかもしれません)。

しかし、この値付近までエラーなく接続を安定して処理するには、後述する次の2つ設定が必要でした。

reuseport設定で各ワーカーに接続を分散させる

同時に大量の接続を行う検証をすると、1つのワーカーに接続が偏る傾向が分かりました。 このため、接続が偏ったワーカーが先行して限界(worker_connections)に達し、とても早い段階でworker_connections are not enoughエラーが発生してしまいました。

[alert] xxxx: *xxxx 1024 worker_connections are not enough while connecting
 to upstream, client: xxxx, server: xxxx, request: "xxxx", upstream: "xxxx", host: "xxxx"

この接続の偏りを解決する方法を調べたところ、reuseport設定を使うことで解決することが分かりました。 resuseport設定を使うと、ソケットのSO_REUSEPORTオプションを利用し、各ワーカーが独自に同じポートに対してソケットをバインドするようになります。 これにより、さきほどの計算式の最大接続数の値の90%程度までエラーなく接続を処理できるようになることを確かめられました。

以下、reuseport設定の注意点です。

reuseportは、listen設定に付与する形になります。 ただし同じIPとポート番号のセットに重複して設定をするとduplicate listen optionsの設定エラーになるので、IPとポート番号のセット毎に1回だけ設定する必要があります。 listenのIPを省略する場合は、0.0.0.0を指定したことになります。

$ nginx -t
nginx: [emerg] duplicate listen options for ...

(-tオプションで設定のバリデーションを行えます)

例:

# IPとポートの組み合わせ毎にreuseportを付与する
server {
    listen 8080 reuseport;
}

server {
    listen 192.168.0.1:8080 reuseport;
}

server {
    listen 192.168.0.2:8080 reuseport;
}

# 重複して付与しないように注意する
server {
    listen 8080;
}

また、reuseportの説明文にセキュリティーに関する注意があります。

Inappropriate use of this option may have its security implications.

この点について説明します。 reuseportを使うと、nginxのワーカープロセスと同じユーザーで実行されている他のプロセスも、そのポートのデータを読めてしまいます。 正しく使用しないとセキュリティー上のリスクとなるため、注意が必要です。 好ましい対策としては、user設定を利用するなどして、nginxのワーカープロセスをnginx専用ユーザーで動作させるように徹底してください。

ファイルディスクリプター数を十分大きくしておく

ファイルディスクリプター数上限の限界に達すると、最大接続数まで余裕があっても次のようなToo many open filesのエラーになってしまいます。

[alert] xxxx: *xxxx socket() failed (24: Too many open files) while
 connecting to upstream, client: xxxx, server: xxxx, request: "xxxx", upstream: "xxxx", host: "xxxx"
[crit] xxxx: accept4() failed (24: Too many open files)

対策として、worker_rlimit_nofileを十分大きな値にしておく(少なくとも想定する最大接続数よりも大きい値にしておく)のが良いです。 この設定により、ワーカープロセスのファイルディスクリプター数上限のソフトリミットとハードリミットの双方を変更することができます。 上限値は、システムとしての1プロセスの上限である/proc/sys/fs/nr_openで定義されている値となります。

例:

$ cat /proc/sys/fs/nr_open
1048576

また、unitファイルにおけるLimitNOFILEでも同様の設定が可能です。 SELinuxのhttpd_setrlimitの制限を受ける場合はworker_rlimit_nofileの設定が失敗するらしいので、その場合はLimitNOFILEの方が良さそうです。

まとめ

本記事では、有名なWebサーバーアプリケーションであるnginxの最大接続数のチューニングについて調査した事例を紹介しました。

以下の点を考慮してチューニングしてください!

  • およその最大接続数 = worker_processes(ワーカープロセス数) * worker_connections(各ワーカーの最大接続数) / 2
    • 2で割る点は、設定によって異なる可能性がある
  • reuseportの設定をしないと、特定のワーカーに接続が偏って早い段階でエラーになることがある
  • worker_rlimit_nofileなどでファイルディスクリプター数上限を大きくしておく必要がある

この調査はクリアコードのFluentd法人様向けサポートサービスの一貫で実施したもので、 Fluentd単体に限らず、このようにFluentdとその周辺のフリーソフトウェア(Redis, Postfix, K8s, Embulkなど)をセットでサポートする事例やご相談もあります。

このようにクリアコードはフリーソフトウェア全般を得意としておりますので、 もしFluentdや周辺のアプリケーションの運用でお困りのことがありましたら、 ぜひお問い合わせフォームからお気軽にご相談ください。

同様のサポート事例として次の記事もあるので、ぜひご覧ください。