Es gibt ziemlich viele "niedrigere" Details.
Stellen Sie sich zunächst vor, der Kernel verfügt über eine Liste von Prozessen. Einige dieser Prozesse werden zu einem bestimmten Zeitpunkt ausgeführt, andere nicht. Der Kernel lässt jedem laufenden Prozess einen Teil der CPU-Zeit zu, unterbricht ihn dann und wechselt zum nächsten. Wenn es keine ausführbaren Prozesse gibt, gibt der Kernel wahrscheinlich eine Anweisung wie HLT an die CPU aus, die die CPU anhält, bis ein Hardware-Interrupt auftritt.
Irgendwo auf dem Server befindet sich ein Systemaufruf mit der Aufschrift "Gib mir etwas zu tun". Es gibt zwei Kategorien von Möglichkeiten, wie dies durchgeführt werden kann. Im Fall von Apache ruft es accept
einen Socket auf, den Apache zuvor geöffnet hat, und überwacht wahrscheinlich Port 80. Der Kernel verwaltet eine Warteschlange mit Verbindungsversuchen und fügt diese Warteschlange jedes Mal hinzu, wenn ein TCP-SYN empfangen wird. Wie der Kernel weiß, dass eine TCP-SYN empfangen wurde, hängt vom Gerätetreiber ab. Bei vielen Netzwerkkarten liegt wahrscheinlich ein Hardware-Interrupt vor, wenn Netzwerkdaten empfangen werden.
accept
bittet den Kernel, mir den nächsten Verbindungsaufbau zurückzugeben. Wenn die Warteschlange nicht leer war, accept
kehrt sie sofort zurück. Wenn die Warteschlange leer ist, wird der Prozess (Apache) aus der Liste der ausgeführten Prozesse entfernt. Wenn später eine Verbindung hergestellt wird, wird der Vorgang fortgesetzt. Dies wird als "Blockieren" bezeichnet, da der aufrufende Prozess accept()
wie eine Funktion aussieht, die erst zurückkehrt, wenn ein Ergebnis vorliegt, das in einiger Zeit vorliegen könnte. Während dieser Zeit kann der Prozess nichts anderes tun.
Nach der accept
Rückkehr weiß Apache, dass jemand versucht, eine Verbindung herzustellen. Anschließend wird fork aufgerufen , um den Apache-Prozess in zwei identische Prozesse aufzuteilen. Einer dieser Prozesse verarbeitet die HTTP-Anforderung, der andere ruft accept
erneut auf, um die nächste Verbindung herzustellen. Daher gibt es immer einen Master-Prozess, der nur accept
Unterprozesse aufruft und erzeugt, und dann gibt es für jede Anforderung einen Unterprozess.
Dies ist eine Vereinfachung: Es ist möglich, dies mit Threads anstelle von Prozessen zu tun, und es ist auch möglich, dies fork
vorher zu tun, damit ein Arbeitsprozess bereit ist, wenn eine Anforderung empfangen wird, wodurch der Startaufwand verringert wird. Abhängig davon, wie Apache konfiguriert ist, kann es eines dieser Dinge tun.
Dies ist die erste allgemeine Kategorie, und sie wird als E / A- Blockierung bezeichnet, da Systemaufrufe wie accept
und read
und write
, die auf Sockets ausgeführt werden, den Prozess anhalten, bis sie etwas zurückgeben können.
Der andere breite Weg, dies zu tun, wird als nicht blockierende oder ereignisbasierte oder asynchrone E / A bezeichnet . Dies wird mit Systemaufrufen wie select
oder implementiert epoll
. Diese tun jeweils dasselbe: Sie geben ihnen eine Liste von Sockets (oder allgemein Dateideskriptoren) und was Sie damit tun möchten, und der Kernel blockiert, bis er bereit ist, eines dieser Dinge zu tun.
Bei diesem Modell können Sie dem Kernel (mit epoll
) mitteilen : "Sagen Sie mir, wenn eine neue Verbindung an Port 80 besteht oder wenn neue Daten auf einer dieser 9471 anderen Verbindungen gelesen werden sollen, die ich geöffnet habe". epoll
blockiert, bis eines dieser Dinge fertig ist, dann machst du es. Dann wiederholst du. Systemaufrufe mögen accept
und read
und werden write
niemals blockiert, zum Teil, weil Sie bei jedem Aufruf epoll
nur erfahren haben, dass sie bereit sind, sodass es keinen Grund zum Blockieren gibt, und weil Sie beim Öffnen des Sockets oder der von Ihnen angegebenen Datei angeben, dass Sie sie möchten Im nicht blockierenden Modus schlagen diese Anrufe fehl, EWOULDBLOCK
anstatt zu blockieren.
Der Vorteil dieses Modells ist, dass Sie nur einen Prozess benötigen. Dies bedeutet, dass Sie nicht für jede Anforderung eine Stapel- und Kernelstruktur zuweisen müssen. Nginx und HAProxy verwenden dieses Modell und es ist ein großer Grund, warum sie mit so viel mehr Verbindungen als Apache auf ähnlicher Hardware umgehen können.