Comment les serveurs Web «écoutent-ils» les adresses IP, les interrompent ou les interrogent?

87

J'essaie de comprendre les détails inférieurs des serveurs Web. Je me demande si un serveur, par exemple Apache, recherche continuellement de nouvelles demandes ou s’il fonctionne avec une sorte de système d’interruption. S'il s'agit d'une interruption, qu'est-ce qui déclenche l'interruption, s'agit-il du pilote de la carte réseau?

utilisateur2202911
la source
1
Le mot clé à comprendre est "serveur" . Dans le modèle serveur-client (par rapport au modèle maître-esclave), le serveur attend les demandes des clients. Ces demandes sont des événements qui doivent être traités. Un serveur Web est un programme d'application. Votre question associe une application logicielle à la terminologie matérielle (par exemple, interruption et carte réseau), plutôt que de conserver les concepts associés sur la même couche d'abstraction. Le pilote de la carte réseau peut en fait parfois utiliser la scrutation; par exemple, les pilotes NAPI Linux reviennent à la scrutation lorsqu'il y a une inondation de paquets. Mais cela n’est pas pertinent pour l’application de traitement d’événements SW.
sciure de bois
1
@sawdust Très intéressant. La question est vraiment destinée à comprendre la connexion entre les processus SW et HW
user2202911
1
Cela ressemble beaucoup à la manière dont les programmes en ligne de commande (et les autres interfaces graphiques) écoutent le clavier. Surtout dans un système de fenêtre, où le noyau reçoit les données du clavier et les transmet au gestionnaire de fenêtres, qui identifie la fenêtre active et transmet les données à cette fenêtre.
G-Man
@ G-Man: Je théorie, oui. En réalité, la plupart des dactylographes ne saisissent pas à 1 Gbit / s, ce qui justifie deux architectures différentes. Un propre, souple et lent, un maladroit mais à grande vitesse.
MSalters

Réponses:

181

La réponse courte est: une sorte de système d'interruption. Ils utilisent essentiellement des E / S bloquantes, ce qui signifie qu'ils dorment (bloquent) en attendant de nouvelles données.

  1. Le serveur crée un socket en écoute, puis se bloque en attendant de nouvelles connexions. Pendant ce temps, le noyau place le processus dans un état de veille interruptible et exécute d'autres processus. C’est un point important: avoir l’enquête de processus continuellement gaspillerait la CPU. Le noyau peut utiliser les ressources système plus efficacement en bloquant le processus jusqu'à ce qu'il y ait du travail à faire.

  2. Lorsque de nouvelles données arrivent sur le réseau, la carte réseau émet une interruption.

  3. Voyant qu'il y a une interruption de la carte réseau, le noyau, via le pilote de carte réseau, lit les nouvelles données de la carte réseau et les stocke en mémoire. (Cela doit être fait rapidement et est généralement géré à l'intérieur du gestionnaire d'interruptions.)

  4. Le noyau traite les données nouvellement arrivées et les associe à un socket. Un processus bloquant sur ce socket sera marqué comme exécutable, ce qui signifie qu'il est maintenant éligible pour être exécuté. Il ne s'exécute pas nécessairement immédiatement (le noyau peut décider de lancer d'autres processus).

  5. À son aise, le noyau réveillera le processus de serveur Web bloqué. (Depuis, il est maintenant exécutable.)

  6. Le processus du serveur Web continue de s'exécuter comme si aucun temps ne s'était écoulé. Son appel système bloquant est renvoyé et toutes les nouvelles données sont traitées. Ensuite ... allez à l'étape 1.

Greg Bowser
la source
18
+1 pour une délimitation claire du noyau par rapport au processus du serveur Web.
Russell Borogove
13
Je ne peux pas croire que quelque chose d'aussi complexe puisse être résumé aussi clairement et simplement, mais vous l'avez fait. +1
Brandon
8
+1 excellente réponse. En outre, les étapes entre 2 et 3 peuvent être un peu plus complexes avec les cartes réseau, les systèmes d’exploitation et les pilotes modernes. Par exemple, avec NAPI sous Linux, les paquets ne sont pas réellement reçus dans un contexte d'interruption. Au lieu de cela, le noyau dit "Ok, carte réseau, je comprends que vous ayez des données. Arrêtez de me bugs (désactivez la source d'interruption), et je serai de retour bientôt pour récupérer ce paquet et tous les paquets suivants qui pourraient arriver avant moi."
Jonathon Reinhart
8
Léger nitpick: Il n'est pas vraiment nécessaire de bloquer. Dès que le processus du serveur a créé un socket en écoute, le noyau accepte les SYN sur ce port, même si vous n'êtes pas bloqué à l'intérieur accept. Elles sont (heureusement, sinon ce serait totalement nul!) Indépendantes, exécutant des tâches de manière asynchrone. Lorsque les connexions arrivent, elles sont placées dans une file d'attente d'où acceptelles sont extraites. Seulement s'il n'y en a pas, il bloque.
Damon
3
"lit les nouvelles données de la carte réseau et les stocke dans la mémoire. (Ceci doit être fait rapidement et est généralement géré dans le gestionnaire d'interruptions.)" N'est-ce pas fait avec un accès direct à la mémoire?
Siyuan Ren
9

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 acceptsur 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.

acceptdemande au noyau de me renvoyer la prochaine connexion initiée. Si la file d'attente n'était pas vide, acceptretourne 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 acceptrevenu, 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 à acceptnouveau pour obtenir la prochaine connexion. Ainsi, il y a toujours un processus maître qui ne fait qu'appeler acceptet 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 forkpré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 acceptet readet writequi 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 selectou 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". epollbloque jusqu’à ce qu’une de ces choses soit prête, alors vous le faites. Ensuite, vous répétez. Appels système comme acceptet readet writejamais bloquer, en partie parce que chaque fois que vous les appelez, epollviens 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 EWOULDBLOCKau 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.

Phil Frost
la source