ブログ | NGINX

NGINX と NGINX Plus における一時ポート枯渇の克服

NGINX-F5 水平黒タイプ RGB の一部
ケビン・ジョーンズ サムネイル
ケビン・ジョーンズ
2016 年 4 月 19 日公開

NGINXNGINX Plus は、非常に強力なHTTPTCP 、およびUDPロードバランサーです。 これらは、大量のリクエストのバーストをプロキシし、多数の同時接続を維持するのに非常に効率的です。 しかし、これらの特性により、NGINX と NGINX Plus は、一時的なポート枯渇(OS が新しいローカル ソケットを確立するために割り当てられたポート番号を使い果たしたために新しい接続を作成できない状態) の影響を受けやすくなります。 (一時ポート枯渇は両方の製品に適用されますが、簡潔にするために、このブログの残りの部分では NGINX Plus についてのみ言及します。)

このブログでは、TCP 接続のコンポーネントと、接続が確立される前にその内容がどのように決定されるかを確認します。 次に、NGINX Plus がエフェメラル ポート枯渇の影響を受けているかを判断する方法を示します。 最後に、Linux カーネルの調整と NGINX Plus ディレクティブの両方を使用してこれらの制限に対処する戦略について説明します。

ネットワークソケットの概要

TCP 経由で接続が確立されると、ローカル ホストとリモート ホストの両方にソケットが作成されます。 これらのソケットは接続されてソケット ペアを作成します。ソケット ペアは、ローカル IP アドレスとポート、およびリモート IP アドレスとポートで構成される一意の 4 組で記述されます。

リモート IP アドレスとポートは接続のサーバー側に属し、接続を開始する前にクライアントによって決定される必要があります。 ほとんどの場合、クライアントは接続に使用するローカル IP アドレスを自動的に選択しますが、接続を確立するソフトウェアによって選択されることもあります。 最後に、オペレーティング システムによって使用可能にされた定義済み範囲からローカル ポートがランダムに選択されます。 ポートは接続期間中のみクライアントに関連付けられるため、一時的と呼ばれます。 接続が終了すると、一時ポートは再利用できるようになります。

一時的なポート枯渇の認識

はじめに述べたように、NGINX Plus は本質的に、一時的なポート枯渇とそれが引き起こす問題の影響を受けます。 NGINX Plus がリクエストをアップストリーム サーバーにプロキシする場合、これは上記のソケット作成プロセスのクライアントであり、デフォルトの動作では、プロキシされたリクエストのソケットが、実行されているホストで使用可能なローカル IP アドレスと一時ポートに自動的にバインドされます。 接続率が高く、確立中のソケットが既存のオープンソケットが閉じられるよりも速く待機状態に移行する場合、最終的に使用可能なポートが使い果たされ、新しいソケットを作成できなくなります。 この結果、オペレーティング システムと NGINX Plus の両方でエラーが発生します。 以下は、NGINX Plus エラー ログに記録されたエラーの例です。

2016/03/18 09:08:37 [crit] 1888#1888: *13 connect() が 10.2.2.77:8081 に失敗しました (99: 要求されたアドレスを割り当てることができません) アップストリームに接続中にクライアント: 10.2.2.42、サーバー: 、リクエスト: 「GET / HTTP/1.1」、アップストリーム:「http://10.2.2.77:8081/」、ホスト: 「10.2.2.77」

ポート枯渇により、500アップストリーム サーバーではなく NGINX Plus によって発生したエラー。 以下は、NGINX Plus アクセス ログのエントリのサンプルです。

10.2.2.42 - - [18/Mar/2016:09:14:20 -0700] 「GET / HTTP/1.1」500 192 "-" "カール/7.35.0"

NGINX Plus サーバー上のTIME-WAIT状態にあるソケットの数を確認するには、Linux シェルで次のssコマンドを実行します。 この例では、ステータスがTIME-WAITのソケットが 143 個開いていることがわかります。 この例では、 wcコマンドを使用してコマンド出力の行数を一覧表示し、カウントを取得します。

# ss -a | grep TIME-WAIT | wc -l143

カーネルを調整して利用可能な一時ポートの数を増やす

一時ポートの枯渇を減らす 1 つの方法は、Linux カーネルのnet.ipv4.ip_local_port_range設定を使用することです。 デフォルトの範囲は、通常 32768 ~ 61000 です。

エフェメラル ポートが不足していることに気付いた場合は、範囲をデフォルトから 1024 ~ 65000 に変更すると、使用可能なエフェメラル ポートの数を 2 倍に増やすことができます。 カーネル設定の変更の詳細については、パフォーマンス向上のための NGINX のチューニングに関するブログ投稿を参照してください。

NGINX Plus でキープアライブ接続を有効にする

一時ポートの枯渇を減らすもう 1 つの方法は、NGINX Plus とアップストリーム サーバー間のキープアライブ接続を有効にすることです。 HTTP の最も単純な実装では、クライアントは新しい接続を開き、要求を書き込み、応答を読み取り、接続を閉じて関連するリソースを解放します。

キープアライブ接続は、クライアントが応答を読み取った後も開いたままになるため、後続のリクエストに再利用できます。

NGINX Plus からアップストリーム サーバーへのキープアライブ接続を有効にするには、 keepaliveディレクティブを使用して、各ワーカー プロセスのキャッシュに保存されるアップストリーム サーバーへのアイドル キープアライブ接続の最大数を定義します。 この数を超えると、最も最近使用されていない接続が閉じられます。 キープアライブがないと、オーバーヘッドが増加し、接続と一時ポートの両方で非効率になります。

次のサンプル設定では、NGINX Plus に対して、 backendというアップストリームブロックで定義されたサーバーへのキープアライブ接続を少なくとも 128 個維持するように指示します。

アップストリーム バックエンド { サーバー 10.0.0.100:1234;
サーバー 10.0.0.101:1234;
キープアライブ 128;
}

アップストリーム サーバーへのキープアライブ接続を有効にする場合は、 proxy_http_versionディレクティブを使用して NGINX Plus に HTTP バージョン 1.1 を使用するように指示し、 proxy_set_headerディレクティブを使用してConnectionという名前のヘッダーを削除する必要もあります。 両方のディレクティブは、 httpserver 、またはlocation構成ブロックに配置できます。

proxy_http_version 1.1; proxy_set_header 接続 "";

定義されたローカル IP アドレスのリストへの接続の動的なバインド

カーネルを最適化し、キープアライブ接続を有効にすると、エフェメラル ポートの可用性と使用をより詳細に制御できるようになりますが、これらの変更だけではエフェメラル ポートの過剰な使用に対抗するには不十分な状況もあります。 この場合、接続の一定割合を静的ローカル IP アドレスにバインドできる NGINX Plus ディレクティブとパラメータをいくつか使用できます。 これにより、使用可能な一時ポートの数と、構成で定義された IP アドレスの数とが実質的に乗算されます。 これを実現するには、 proxy_bindおよびsplit_clientsディレクティブを使用します。

以下の設定例では、 locationブロックのproxy_bindディレクティブは、 $split_ip変数の値に従って、各リクエスト中にローカル IP アドレスを設定します。 この変数は、ハッシュ関数を使用して値を決定するsplit_clientsブロックによって生成された値に動的に設定します。

split_clientsディレクティブの最初のパラメータは文字列 ( "$remote_addr$remote_port" ) であり、各リクエスト中にMurmurHash2関数を使用してハッシュされます。 2 番目のパラメータ ( $split_ip ) は、最初のパラメータのハッシュに基づいて動的に設定する変数です。

中括弧内のステートメントはハッシュ テーブルを「バケット」に分割し、各バケットにはハッシュの一定の割合が含まれます。 ここでは、テーブルを同じサイズの 10 個のバケットに分割していますが、任意の数のバケットを作成でき、バケットがすべて同じサイズである必要はありません。 (ハッシュの数が指定されたパーセンテージに均等に分割できない場合があるため、最後のバケットのパーセンテージは特定の数値ではなく、常にアスタリスク [ * ] で表されます。)

可能なハッシュ値の範囲は 0 から 4294967295 なので、この場合、各バケットには約 429496700 個の値 (全体の 10%) が含まれます。最初のバケットには 0 から 429496700 までの値、2 番目のバケットには 429496701 から 858993400 までの値、というようになります。 $split_ip変数は、$remote_addr$remote_port文字列のハッシュを含むバケットに関連付けられた IP アドレスに設定されます。 具体的な例として、ハッシュ値 150000000 は 4 番目のバケットに含まれるため、その場合、変数$split_ipは動的に 10.0.0.213 に設定されます。

http { アップストリーム バックエンド { サーバー 10.0.0.100:1234; サーバー 10.0.0.101:1234; } サーバー { # ... 場所 / { # ... proxy_pass http://backend; proxy_bind $split_ip; proxy_set_header X-Forwarded-For $remote_addr; } } split_clients "$remote_addr$remote_port" $split_ip { 10% 10.0.0.210; 10% 10.0.0.211; 10% 10.0.0.212; 10% 10.0.0.213; 10% 10.0.0.214; 10% 10.0.0.215; 10% 10.0.0.216; 10% 10.0.0.217; 10% 10.0.0.218; * 10.0.0.219; } }

結論

一時ポートの数に関する Linux カーネル設定を微調整すると、可用性と使用効率が向上します。 NGINX Plus からアップストリーム サーバーへのキープアライブ接続を有効にすると、一時ポートの消費がより効率的になります。 最後に、NGINX Plus 設定でsplit_clientsおよびproxy_bindディレクティブを使用すると、発信接続を定義済みのローカル IP アドレスのリストに動的にバインドできるため、NGINX Plus で使用できる一時ポートの数が大幅に増加します。

NGINX Plus をお試しいただくには、今すぐ30 日間の無料トライアルを開始するか、弊社にお問い合わせの上、使用事例についてご相談ください


「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"