ホームページ >運用・保守 >Nginx >高負荷ネットワーク向けに Nginx と Node.js を最適化する方法

高負荷ネットワーク向けに Nginx と Node.js を最適化する方法

PHPz
PHPz転載
2023-05-17 15:13:141516ブラウズ

ネットワークチューニング
まずnginxとnode.jsの基礎となる送信メカニズムを理解し、ターゲットを絞った最適化を実行しないと、2つのチューニングをどれほど詳細に行ったとしても、無駄です。通常、nginx は tcp ソケットを介してクライアントと上流アプリケーションを接続します。
私たちのシステムには、カーネル パラメータを通じて設定される tcp のしきい値と制限が多数あります。これらのパラメータのデフォルト値は一般的な目的のために設定されていることが多く、Web サーバーの高トラフィックと短い寿命の要件を満たすことができません。
TCP を調整するためのパラメーターをいくつか示します。これらを有効にするには、それらを /etc/sysctl.conf ファイルに入れるか、/etc/sysctl.d/99-tuning.conf などの新しい構成ファイルに入れてから sysctl -p を実行します。カーネルにそれらをロードさせます。この物理的な作業には sysctl-cookbook を使用します。
ここにリストされている値は安全に使用できますが、負荷、ハードウェア、および使用状況に基づいてより適切な値を選択するために、各パラメーターの意味を検討することをお勧めします。

コードをコピーしますコードは次のとおりです:

net .ipv4.ip_local_port_range='1024 65000'
net.ipv4.tcp_tw_reuse='1'
net.ipv4.tcp_fin_timeout='15'
net.core.netdev_max_backlog='4096'
net. core.rmem_max ='16777216'
net.core.somaxconn='4096'
net.core.wmem_max='16777216'
net.ipv4.tcp_max_syn_backlog='20480'
net.ipv4。 tcp_max_tw_buckets=' 400000'
net.ipv4.tcp_no_metrics_save='1'
net.ipv4.tcp_rmem='4096 87380 16777216'
net.ipv4.tcp_syn_retries='2'
net.ipv4。 tcp_synack_retries=' 2'
net.ipv4.tcp_wmem='4096 65536 16777216'
vm.min_free_kbytes='65536'

重要なもののいくつかを強調表示します。
net.ipv4.ip_local_port_range
上流アプリケーションのために下流クライアントにサービスを提供するには、nginx は 2 つの TCP 接続を開く必要があります。1 つはクライアントに接続し、もう 1 つはアプリケーションに接続します。サーバーが多数の接続を受信すると、システムの使用可能なポートがすぐに枯渇してしまいます。 net.ipv4.ip_local_port_range パラメータを変更すると、使用可能なポートの範囲を増やすことができます。 /var/log/syslog で「ポート 80 で syn フラッディングが発生している可能性があります。Cookie を送信しています」というエラーが見つかった場合は、システムが使用可能なポートを見つけられないことを意味します。 net.ipv4.ip_local_port_range パラメータを増やすと、このエラーを減らすことができます。
net.ipv4.tcp_tw_reuse
サーバーが多数の TCP 接続を切り替える必要がある場合、time_wait 状態の接続が多数生成されます。 time_wait は、接続自体は閉じられていますが、リソースは解放されていないことを意味します。 net_ipv4_tcp_tw_reuse を 1 に設定すると、カーネルは安全なときに接続をリサイクルしようとします。これは、新しい接続を再確立するよりもはるかに安価です。
net.ipv4.tcp_fin_timeout
これは、time_wait 状態の接続がリサイクルするまで待機する必要がある最小時間です。小さくすることでリサイクルを早めることができます。
接続ステータスを確認する方法
netstat:
netstat -tan | awk '{print $6}' | sort | uniq -c
または ss:
を使用します。 ss - s
nginx
ss -s
total: 388 (カーネル 541)
tcp: 47461 (estab 311、クローズド 47135、孤立 4、synrecv 0、timewait 47135/0)、ポート 33938
トランスポート合計 ip ipv6
* 541 - -
raw 0 0 0
udp 13 10 3
tcp 326 325 1
inet 339 335 4
frag 0 0 0
Web サーバーの負荷が徐々に増加すると、nginx の奇妙な制限に遭遇し始めます。接続が切断され、カーネルは syn フラッドを報告し続けます。現時点では、負荷平均と CPU 使用率は非常に小さく、サーバーは明らかにより多くの接続を処理できるため、非常にイライラします。
調査の結果、time_wait 状態の接続が多数あることが判明しました。これはサーバーの 1 つからの出力です:
time_wait 接続が 47,135 個あります!また、ss を見ると、それらはすべて閉じた接続であることがわかります。これは、サーバーが使用可能なポートのほとんどを消費したことを示し、サーバーが接続ごとに新しいポートを割り当てていることも意味します。ネットワークを調整することで問題は少し解決しましたが、それでも十分なポートがありませんでした。
さらに調査した結果、アップストリーム接続キープアライブ ディレクティブに関するドキュメントを見つけました:
アップストリーム サーバーへのアイドル キープアライブ接続の最大数を設定します。これらの接続はワーカー プロセスのキャッシュに保持されます。 。 ###面白い。理論的には、この設定では、キャッシュされた接続を介してリクエストを渡すことにより、無駄な接続が最小限に抑えられます。ドキュメントには、proxy_http_version を「1.1」に設定し、「connection」ヘッダーをクリアする必要があるとも記載されています。さらに調査した結果、http/1.1 は http1.0 に比べて tcp 接続の使用を大幅に最適化し、nginx はデフォルトで http/1.0 を使用するため、これは良いアイデアであることがわかりました。
ドキュメントの推奨事項に従って変更すると、アップリンク構成ファイルは次のようになります:

コードをコピーします。コードは次のとおりです:

アップストリーム backend_nodejs {
サーバー nodejs-3:5016 max_fails=0 フェイル_タイムアウト=10s;
サーバー ノードjs-4:5016 max_fails=0 フェイルタイムアウト=10秒;
サーバー ノードjs-5:5016 max_fails=0また、提案に従ってサーバー セクションのプロキシ設定も変更しました。 。同時に、失敗したサーバーをスキップするために proxy_next_upstream が追加され、クライアントの keepalive_timeout が調整され、アクセス ログがオフになりました。構成は次のようになります。


コードをコピーします。コードは次のとおりです。

server {
listen 80;

server_name fast.gosquared.com;

client_max_body_size 16m;

keepalive_timeout 10;

location / {
proxy_next_upstream エラー タイムアウト http_500 http_502 http_503 http_504;
proxy_set_header 接続 "";
proxy_http_version 1.1;
proxy_pass http://backend_nodejs;
}
access_log off;
error_log /dev/null crit;
}

新しい構成を採用した後、サーバーが占有するソケットが 90% 削減されたことがわかりました。 。はるかに少ない接続を使用してリクエストを送信できるようになりました。新しい出力は次のとおりです。
ss -s
total: 558 (kernel 604)
tcp: 4675 (estab 485、closed 4183、orphaned 0、synrecv 0、timewait 4183/0)、ports 2768

transport total ip ipv6

* 604 - -
raw 0 0 0
udp 13 10 3
tcp 492 491 1
inet 505 501 4
node.js
got I/O を非同期に処理するイベント駆動型の設計のおかげで、Node.js はすぐに大量の接続とリクエストを処理できます。他にもチューニング方法はありますが、この記事では主にnode.jsのプロセス面に焦点を当てます。
ノードはシングルスレッドであり、複数のコアを自動的に使用しません。つまり、アプリケーションはサーバーのすべての機能を自動的に取得できません。

ノード プロセスのクラスタリングの実現

複数のスレッドをフォークし、同じポートでデータを受信するようにアプリケーションを変更することで、負荷が複数のコアにまたがることが可能になります。 Node には、この目標を達成するために必要なすべてのツールを提供するクラスター モジュールがありますが、それらをアプリケーションに追加するには多くの手作業が必要です。 Expressを使用している場合、eBayにはcluster2というモジュールがあり、それを使用できます。

コンテキスト切り替えの防止複数のプロセスを実行する場合、各 CPU コアが同時に 1 つのプロセスのみでビジーになるようにする必要があります。一般に、CPU に n 個のコアがある場合、n-1 個のアプリケーション プロセスを生成する必要があります。これにより、各プロセスが適切なタイム スライスを取得し、カーネル スケジューラが他のタスクを実行できるように 1 つのコアが空きます。また、CPU 競合を防ぐために、基本的に、node.js 以外の他のタスクがサーバー上で実行されないようにする必要もあります。
私たちはかつて間違いを犯し、サーバー上に 2 つの Node.js アプリケーションをデプロイしてしまい、各アプリケーションが n-1 個のプロセスを開きました。その結果、CPU を奪い合うことになり、システム負荷が急激に上昇します。当社のサーバーはすべて 8 コア マシンですが、コンテキストの切り替えによって生じるパフォーマンスのオーバーヘッドは依然としてはっきりと感じられます。コンテキストスイッチングとは、CPU が他のタスクを実行するために現在のタスクを一時停止する現象を指します。切り替えるとき、カーネルは現在のプロセスのすべての状態を一時停止してから、別のプロセスをロードして実行する必要があります。この問題を解決するために、各アプリケーションが起動するプロセスの数を減らし、CPU を公平に共有できるようにし、その結果、システムの負荷が軽減されました。 # 上の図に注目してください。システム負荷 (青線) が CPU コア数 (赤線) を下回る様子を確認してください。他のサーバーでも同じことが確認されました。合計のワークロードは変わらないため、上のグラフのパフォーマンスの向上はコンテキスト スイッチの減少によるものとしか考えられません。

以上が高負荷ネットワーク向けに Nginx と Node.js を最適化する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。