NGINX は Web パフォーマンスでトップを走っていますが、それはすべてソフトウェアの設計方法によるものです。 多くの Web サーバーやapplicationサーバーが単純なスレッドベースまたはプロセスベースのアーキテクチャを使用しているのに対し、NGINX は、最新のハードウェア上で数十万の同時接続に拡張できる洗練されたイベント駆動型アーキテクチャを採用しています。
Inside NGINXインフォグラフィックでは、高レベルのプロセス アーキテクチャから掘り下げて、NGINX が単一のプロセス内で複数の接続を処理する方法を説明します。 このブログでは、その仕組みをさらに詳しく説明します。
この設計をよりよく理解するには、NGINX がどのように実行されるかを理解する必要があります。 NGINX には、マスター プロセス (構成の読み取りやポートへのバインドなどの特権操作を実行) と、多数のワーカー プロセスおよびヘルパー プロセスがあります。
# service nginx restart * nginx を再起動しています # ps -ef --forest | grep nginx root 32475 1 0 13:36 ? 00:00:00 nginx: マスター プロセス /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 32476 32475 0 13:36 ? 00:00:00 _ nginx: ワーカープロセス nginx 32477 32475 0 13:36 ? 00:00:00 _ nginx: ワーカープロセス nginx 32479 32475 0 13:36 ? 00:00:00 _ nginx: ワーカープロセス nginx 32480 32475 0 13:36 ? 00:00:00 _ nginx: ワーカープロセス nginx 32481 32475 0 13:36 ? 00:00:00 _ nginx: キャッシュ マネージャー プロセス nginx 32482 32475 0 13:36 ? 00:00:00 _ nginx: キャッシュローダープロセス
この 4 コア サーバーでは、NGINX マスター プロセスが 4 つのワーカー プロセスと、ディスク上のコンテンツ キャッシュを管理するいくつかのキャッシュ ヘルパー プロセスを作成します。
あらゆる Unixapplicationの基本的な基盤は、スレッドまたはプロセスです。 (Linux OS の観点から見ると、スレッドとプロセスはほぼ同じですが、主な違いはメモリを共有する程度です。) スレッドまたはプロセスは、オペレーティング システムが CPU コア上で実行するようにスケジュールできる、自己完結型の命令セットです。 ほとんどの複雑なapplicationsでは、次の 2 つの理由により、複数のスレッドまたはプロセスを並行して実行します。
プロセスとスレッドはリソースを消費します。 それぞれがメモリやその他の OS リソースを使用するため、コア上でスワップオン/オフする必要があります (コンテキスト スイッチと呼ばれる操作)。 最近のサーバーのほとんどは、数百の小さなアクティブなスレッドまたはプロセスを同時に処理できますが、メモリが使い果たされたり、I/O 負荷が高くなって大量のコンテキスト スイッチが発生すると、パフォーマンスが大幅に低下します。
ネットワークapplicationsを設計する一般的な方法は、各接続にスレッドまたはプロセスを割り当てることです。 このアーキテクチャはシンプルで実装も簡単ですが、applicationが数千の同時接続を処理する必要がある場合は拡張できません。
NGINX は、利用可能なハードウェア リソースに合わせて調整された予測可能なプロセス モデルを使用します。
ほとんどの場合に推奨される NGINX 構成 (CPU コアごとに 1 つのワーカー プロセスを実行する) では、ハードウェア リソースが最も効率的に使用されます。 これを設定するには、 worker_processes
ディレクティブでauto
パラメータを設定します。
ワーカープロセスは自動です。
NGINX サーバーがアクティブな場合、ワーカー プロセスのみがビジー状態になります。 各ワーカー プロセスは複数の接続を非ブロッキング方式で処理し、コンテキスト スイッチの数を削減します。
各ワーカー プロセスはシングル スレッドであり、独立して実行され、新しい接続を取得して処理します。 プロセスは、共有キャッシュ データ、セッション永続データ、およびその他の共有リソース用の共有メモリを使用して通信できます。
各 NGINX ワーカー プロセスは NGINX 構成で初期化され、マスター プロセスによって一連の listen ソケットが提供されます。
NGINX ワーカー プロセスは、リッスン ソケット ( accept_mutexおよびカーネル ソケット シャーディング) 上のイベントを待機することから始まります。 イベントは新しい着信接続によって開始されます。 これらの接続はステート マシンに割り当てられます。最も一般的に使用されるのは HTTP ステート マシンですが、NGINX はストリーム (生の TCP) トラフィックやさまざまなメール プロトコル (SMTP、IMAP、POP3) 用のステート マシンも実装しています。
ステート マシンは基本的に、NGINX にリクエストの処理方法を指示する一連の命令です。 NGINX と同じ機能を実行するほとんどの Web サーバーは同様のステート マシンを使用しますが、違いは実装にあります。
ステートマシンをチェスのルールのようなものだと考えてください。 各 HTTP トランザクションはチェス ゲームです。 チェス盤の片側にはウェブ サーバーがいます。これは、非常に迅速に決定を下すことができるグランドマスターです。 もう一方の側は、比較的低速なネットワーク経由でサイトまたはapplicationにアクセスしている Web ブラウザーであるリモート クライアントです。
ただし、ゲームのルールは非常に複雑になる場合があります。 たとえば、Web サーバーは他のパーティと通信したり (アップストリームapplicationにプロキシする)、認証サーバーと通信したりする必要がある場合があります。 Web サーバー内のサードパーティ モジュールは、ゲームのルールを拡張することもできます。
プロセスまたはスレッドは、オペレーティング システムが CPU コア上で実行するようにスケジュールできる、自己完結型の命令セットであると説明したことを思い出してください。 ほとんどの Web サーバーと Webapplicationsは、接続ごとのプロセスまたは接続ごとのスレッドモデルを使用してチェス ゲームをプレイします。 各プロセスまたはスレッドには、1 つのゲームを最後までプレイするための命令が含まれています。 プロセスがサーバーによって実行されている間、プロセスはほとんどの時間を「ブロック」された状態、つまりクライアントが次の動作を完了するのを待機して過ごします。
覚えておくべき重要な点は、すべてのアクティブな HTTP 接続 (すべてのチェス ゲーム) には専用のプロセスまたはスレッド (グランドマスター) が必要であるということです。 このアーキテクチャはシンプルで、サードパーティのモジュール(「新しいルール」)を使用して簡単に拡張できます。 しかし、大きな不均衡があります。ファイル記述子と少量のメモリによって表される、かなり軽量な HTTP 接続が、非常に重いオペレーティング システム オブジェクトである別のスレッドまたはプロセスにマップされます。 これはプログラミング上の利便性ですが、非常に無駄が多いです。
チェスのグランドマスター 1 人が同時に数十人の対戦相手と対戦する同時エキシビションゲームについて聞いたことがあるでしょうか。
これが、NGINX ワーカー プロセスが「チェス」をプレイする方法です。 各ワーカー(通常は CPU コアごとに 1 つのワーカーがあることに注意してください)は、数百(実際には数十万)のゲームを同時にプレイできるグランドマスターです。
ワーカーは、ネットワーク トラフィックをブロックして、「相手」(クライアント) が応答するのを待つことはありません。 ワーカーは、自分の動きを終えると、すぐに動きの処理を待っている他のゲームに進むか、新しいプレイヤーを迎え入れます。
NGINX は、ワーカー プロセスごとに数十万の接続をサポートできるほど優れたスケーラビリティを備えています。 新しい接続ごとに別のファイル記述子が作成され、ワーカー プロセスで少量の追加メモリが消費されます。 接続ごとに追加のオーバーヘッドはほとんどありません。 NGINX プロセスは CPU に固定されたままになります。 コンテキストの切り替えは比較的まれであり、実行する作業がないときに発生します。
プロセスごとに接続をブロックするアプローチでは、各接続に大量の追加リソースとオーバーヘッドが必要になり、コンテキスト スイッチ (あるプロセスから別のプロセスへの切り替え) が非常に頻繁に発生します。
より詳細な説明については、NGINX, Inc. のコーポレート開発担当副社長兼共同創設者である Andrew Alexeev による NGINX アーキテクチャに関するこちらの記事をご覧ください。
適切なシステムチューニングを行うことで、NGINX はワーカープロセスごとに数十万の同時 HTTP 接続を処理できるように拡張でき、トラフィックの急増 (新しいゲームの流入) を問題なく吸収できます。
NGINX のプロセス アーキテクチャは、ワーカー プロセスの数が少ないため、構成の更新だけでなく、NGINX バイナリ自体の更新も非常に効率的に行えます。
NGINX 設定の更新は非常にシンプルで軽量、かつ信頼性の高い操作です。 通常は、 nginx
-s
reload
コマンドを実行することを意味し、このコマンドはディスク上の構成をチェックし、マスター プロセスに SIGHUP 信号を送信します。
マスター プロセスは SIGHUP を受信すると、次の 2 つの処理を実行します。
このリロード プロセスにより、CPU とメモリの使用量がわずかに増加する可能性がありますが、アクティブな接続によるリソース負荷と比較すると、通常は気付かない程度です。 1 秒間に複数回設定をリロードできます (多くの NGINX ユーザーがまさにそれを行っています)。 非常にまれに、接続の終了を待機している NGINX ワーカー プロセスが多数存在する場合に問題が発生しますが、その場合でもすぐに解決されます。
NGINX のバイナリ アップグレード プロセスは、高可用性の究極の目標を実現します。接続が切断されたり、ダウンタイムが発生したり、サービスが中断したりすることなく、ソフトウェアをオンザフライでアップグレードできます。
バイナリ アップグレード プロセスは、構成の正常なリロードのアプローチに似ています。 新しい NGINX マスター プロセスは元のマスター プロセスと並行して実行され、リスニング ソケットを共有します。 両方のプロセスがアクティブであり、それぞれのワーカー プロセスがトラフィックを処理します。 その後、古いマスターとそのワーカーに正常に終了するように信号を送ることができます。
プロセス全体については、 「NGINX の制御」で詳しく説明されています。
Inside NGINX インフォグラフィックは、 NGINX の機能の概要を示していますが、このシンプルな説明の背後には、10 年以上にわたるイノベーションと最適化があり、NGINX は、最新の Webapplicationsに必要なセキュリティと信頼性を維持しながら、幅広いハードウェアで最高のパフォーマンスを実現しています。
NGINX の最適化について詳しく知りたい場合は、次の優れたリソースをご覧ください。
SO_REUSEPORT
ソケット オプションを使用)「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"