Il y a beaucoup de détails "inférieurs".
Tout d’abord, considérons que le noyau a une liste de processus et qu’à un moment donné, certains de ces processus sont en cours d’exécution et d’autres pas. Le noyau accorde à chaque processus en cours une tranche de temps CPU, puis l'interrompt et passe au suivant. S'il n'y a pas de processus exécutables, le noyau enverra probablement une instruction telle que HLT à la CPU qui suspend la CPU jusqu'à ce qu'une interruption matérielle se produise.
Quelque part sur le serveur se trouve un appel système qui dit "donne-moi quelque chose à faire". Il existe deux grandes catégories de façons de procéder. Dans le cas d’Apache, il appelle accept
sur un socket déjà ouvert par Apache, probablement en écoutant sur le port 80. Le noyau conserve une file d’attentes de connexion et s’ajoute à cette file chaque fois qu’un TCP SYN est reçu. La manière dont le noyau sait qu'un TCP SYN a été reçu dépend du pilote de périphérique. pour de nombreuses cartes réseau, il y a probablement une interruption matérielle lorsque les données du réseau sont reçues.
accept
demande au noyau de me renvoyer la prochaine connexion initiée. Si la file d'attente n'était pas vide, accept
retourne immédiatement. Si la file d'attente est vide, le processus (Apache) est supprimé de la liste des processus en cours d'exécution. Lorsqu'une connexion est établie ultérieurement, le processus est repris. Cela s'appelle "bloquer", car pour le processus qui l'appelle, cela accept()
ressemble à une fonction qui ne retourne pas avant d'avoir un résultat, ce qui pourrait être dans un certain temps. Pendant ce temps, le processus ne peut rien faire d’autre.
Une fois accept
revenu, Apache sait que quelqu'un tente d'établir une connexion. Il appelle ensuite fork pour diviser le processus Apache en deux processus identiques. L'un de ces processus traite ensuite la demande HTTP, l'autre appelle à accept
nouveau pour obtenir la prochaine connexion. Ainsi, il y a toujours un processus maître qui ne fait qu'appeler accept
et générer des sous-processus, puis il y a un sous-processus pour chaque demande.
Ceci est une simplification: il est possible de faire cela avec des threads au lieu de processus, mais il est également possible de le faire au fork
préalable pour qu'un processus de travail soit prêt à démarrer lorsqu'une demande est reçue, réduisant ainsi le temps système nécessaire au démarrage. En fonction de la configuration d’Apache, il est possible que l’une de ces choses soit remplie.
Il s’agit de la première catégorie générale de procédures , appelée blocage d'IO, car les appels système tels que accept
et read
et write
qui fonctionnent sur des sockets suspendent le processus jusqu'à ce qu'ils aient quelque chose à retourner.
L'autre façon de procéder consiste à utiliser des E / S asynchrones ou non bloquantes . Ceci est mis en œuvre avec des appels système tels que select
ou epoll
. Ils font chacun la même chose: vous leur donnez une liste de sockets (ou en général, des descripteurs de fichier) et ce que vous voulez en faire, et le noyau se bloque jusqu'à ce qu'il soit prêt à faire l'une de ces choses.
Avec ce modèle, vous pourriez dire au noyau (avec epoll
): "Dis-moi quand une nouvelle connexion sur le port 80 ou de nouvelles données seront lues sur l'une de ces 9471 autres connexions que j'ai ouvertes". epoll
bloque jusqu’à ce qu’une de ces choses soit prête, alors vous le faites. Ensuite, vous répétez. Appels système comme accept
et read
et write
jamais bloquer, en partie parce que chaque fois que vous les appelez, epoll
viens de vous dire qu'ils sont prêts donc il n'y aurait aucune raison de bloquer, et aussi parce que lorsque vous ouvrez la prise ou le fichier que vous spécifiez que vous les voulez en mode non bloquant, ces appels échoueront avec EWOULDBLOCK
au lieu de bloquer.
L'avantage de ce modèle est que vous n'avez besoin que d'un seul processus. Cela signifie que vous n'avez pas besoin d'allouer une pile et des structures de noyau pour chaque requête. Nginx et HAProxy utilisent ce modèle, et c'est l'une des principales raisons pour lesquelles ils peuvent gérer autant de connexions qu'Apache sur un matériel similaire.