Webサーバーの下位の詳細を理解しようとしています。サーバー(Apacheなど)が新しいリクエストを継続的にポーリングしているか、または何らかの割り込みシステムで機能しているかどうかを考えています。それが割り込みである場合、何がその割り込みを引き起こしているのですか、それはネットワークカードドライバですか?
簡単に言えば、ある種の割り込みシステムです。基本的に、それらはブロッキングI/Oを使用します。つまり、新しいデータを待つ間、スリープ(ブロック)します。
サーバーはリスニングソケットを作成し、新しい接続を待機している間ブロックします。この間、カーネルはプロセスをinterruptible sleep状態にして、他のプロセスを実行します。これは重要なポイントです。プロセスを継続的にポーリングすると、CPUが浪費されます。カーネルは、実行する作業がなくなるまでプロセスをブロックすることにより、システムリソースをより効率的に使用できます。
新しいデータがネットワークに到着すると、ネットワークカードは割り込みを発行します。
ネットワークカードからの割り込みがあることを確認すると、カーネルはネットワークカードドライバを介して、ネットワークカードから新しいデータを読み取り、メモリに格納します。 (これは迅速に実行する必要があり、通常は割り込みハンドラー内で処理されます。)
カーネルは、新しく到着したデータを処理し、それをソケットに関連付けます。そのソケットでブロックされているプロセスは、実行可能とマークされます。つまり、実行できるようになります。必ずしもすぐに実行されるとは限りません(カーネルが他のプロセスを実行することを決定する場合があります)。
余暇に、カーネルはブロックされたWebサーバープロセスを起動します。 (現在は実行可能であるため)。
Webサーバープロセスは、時間が経過していないかのように実行を継続します。そのブロッキングシステムコールが戻り、新しいデータを処理します。次に...手順1に進みます。
「下位」の詳細はかなりたくさんあります。
まず、カーネルにはプロセスのリストがあり、常に、これらのプロセスの一部は実行中、一部は実行されていないことを考慮してください。カーネルは、実行中の各プロセスにCPU時間の一部を許可し、それを中断して次のプロセスに移動します。実行可能なプロセスがない場合、カーネルはおそらく [〜#〜] hlt [〜#〜] のような命令をCPUに発行し、ハードウェア割り込みが発生するまでCPUを一時停止します。
サーバーのどこかに システムコール があり、「何かをしてくれ」と言っています。これを行う方法には、大きく分けて2つのカテゴリがあります。 Apacheの場合、Apacheが以前に開いたソケットで accept
を呼び出し、おそらくポート80でリッスンします。カーネルは接続試行のキューを維持し、そのキューに時間 TCP SYN が受信されます。カーネルがどのようにTCP= SYNを受信したか)を知るかは、デバイスドライバーによって異なります。多くのNICの場合、ネットワークデータを受信したときにハードウェア割り込みが発生する可能性があります。
accept
は、カーネルに次の接続開始を私に返すように要求します。キューが空でなければ、accept
はただちに戻ります。キューが空の場合、プロセス(Apache)は実行中のプロセスのリストから削除されます。後で接続が開始されると、プロセスが再開されます。これは「ブロッキング」と呼ばれます。これは、それを呼び出すプロセスにとって、accept()
が、結果が出るまで返らない関数のように見えるためです。その間、プロセスは他に何もできません。
accept
が返されると、Apacheは誰かが接続を開始しようとしていることを認識します。次に fork を呼び出して、Apacheプロセスを2つの同一のプロセスに分割します。これらのプロセスの1つはHTTP要求の処理を続行し、他のプロセスは次の接続を取得するために再度accept
を呼び出します。したがって、常にaccept
を呼び出してサブプロセスを生成する以外に何もしないマスタープロセスがあり、リクエストごとに1つのサブプロセスがあります。
これは単純化です。これをプロセスの代わりにスレッドで実行することも可能です。また、事前にfork
を実行して、リクエストを受信したときにすぐに実行できるワーカープロセスを用意して、起動のオーバーヘッドを減らすこともできます。 Apacheの構成方法に応じて、Apacheはこれらのいずれかを実行します。
これは、その方法の最初の大まかなカテゴリであり、システムはaccept
やread
とwrite
は、ソケットで動作し、何か返されるまでプロセスを一時停止します。
それを行う他の広範な方法は、非ブロッキングまたはイベントベースまたは 非同期IO と呼ばれます。これは select
または epoll
のようなシステムコールで実装されます。これらはそれぞれ同じことを行います。ソケット(または一般的にはファイル記述子)のリストと、ソケットで何をしたいかを指定し、カーネルがそれらのいずれかを実行する準備ができるまでブロックします。
このモデルを使用すると、カーネルに(epoll
を使用して)、「ポート80に新しい接続があるか、開いているこれらの9471のその他の接続のいずれかで読み取る新しいデータがある場合に通知する」と伝えることができます。 epoll
は、これらのいずれかの準備ができるまでブロックし、それからそれを行います。その後、繰り返します。 accept
やread
やwrite
のようなシステムコールはブロックしません。これは、コールするたびにepoll
が準備ができていることを通知するためです。 dブロックする理由はありません。また、ソケットまたはファイルを開いたときに、それらを非ブロックモードで使用するように指定しているため、これらの呼び出しは EWOULDBLOCK
で失敗しますブロッキング。
このモデルの利点は、必要なプロセスが1つだけであることです。つまり、リクエストごとにスタックとカーネル構造を割り当てる必要はありません。 Nginx と HAProxy がこのモデルを使用しているため、同様のハードウェアでApacheよりもはるかに多くの接続を処理できる大きな理由です。