Question Comment les serveurs Web "écoutent-ils" les adresses IP, les interruptions ou les interrogations?


J'essaie de comprendre les moindres détails des serveurs Web. Je me demande si un serveur, par exemple Apache, interroge en permanence de nouvelles requêtes ou s'il fonctionne par 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?


86
2017-11-09 20:39


origine


Le mot-clé à comprendre est "serveur". Dans le modèle client-serveur (par rapport au modèle maître-esclave), le serveur attend pour les demandes des clients. Ces demandes sont événements qui doivent être entretenus. Un serveur Web est un programme d'application. Votre question combine l'application logicielle avec la terminologie matérielle (par exemple, l'interruption et la carte réseau), plutôt que de conserver les concepts associés sur la même couche d'abstraction. Le pilote de carte réseau utilise parfois l'interrogation, par ex. Les pilotes NAPI Linux régressent à l'interrogation lorsqu'il y a un flot de paquets. Mais cela n'a rien à voir avec le logiciel de traitement des événements. - sawdust
@sawdust Très intéressant. La question est vraiment de comprendre le lien entre les processus SW et HW - user2202911
C'est très similaire à la façon dont les programmes en ligne de commande (et 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 qui a le focus et les transmet à cette fenêtre. - G-Man
@ G-Man: je théorie, oui. En réalité, la plupart des dactylographes ne tapent pas à 1 Gbit / s, ce qui justifie d'avoir deux architectures différentes. Un propre, flexible et lent, un maladroit mais rapide. - MSalters


Réponses:


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

  1. Le serveur crée un socket d'écoute, puis se bloque en attendant de nouvelles connexions. Pendant ce temps, le noyau met le processus dans un sommeil interruptible état et exécute d'autres processus. C'est un point important: si le processus de sondage était continuellement gaspillé, la CPU serait perdue. Le noyau peut utiliser les ressources du 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 la 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é dans le gestionnaire d'interruption.)

  4. Le noyau traite les données nouvellement arrivées et les associe à un socket. Un processus qui bloque sur ce socket sera marqué comme étant 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 d'exécuter d'autres processus encore).

  5. A loisir, le noyau va réveiller le processus de serveur Web bloqué. (Depuis qu'il est maintenant exécutable.)

  6. Le processus du serveur Web continue de s’exécuter comme si aucune heure ne s’était écoulée. Son appel système bloquant retourne et traite toutes les nouvelles données. Alors ... allez à l'étape 1.


181
2017-11-09 21:14



+1 pour une délimitation claire du noyau par rapport au processus du serveur Web. - Russell Borogove
Je ne peux pas croire quelque chose d'aussi complexe que cela peut être résumé si clairement et simplement, mais vous l'avez fait. +1 - Brandon
+1 Bonne réponse. De plus, les étapes entre 2 et 3 peuvent devenir un peu plus complexes avec les cartes réseau, les systèmes d'exploitation et les pilotes modernes. Par exemple, avec NAPI sur Linux, les paquets ne sont pas réellement reçus dans un contexte d'interruption. Au lieu de cela, le noyau dit "Ok, NIC, je crois comprendre que vous avez des données. Quittez le bugging (désactivez la source d’interruption), et je serai de retour bientôt pour récupérer ce paquet. et tous les paquets ultérieurs qui pourraient arriver avant moi. " - Jonathon Reinhart
Léger nitpick: Il n'est pas vraiment nécessaire de bloquer. Dès que le processus serveur a créé un socket d'écoute, le noyau accepte les SYN sur ce port, même si vous n'êtes pas bloqué à l'intérieur. accept. Ils sont (heureusement ou cela ferait totalement chier!) Des tâches indépendantes et asynchrones. À mesure que les connexions entrent, elles sont placées dans une file d'attente où accept les tire de. Seulement s'il n'y en a pas, ça bloque. - Damon
"lit les nouvelles données de la carte réseau et les stocke en mémoire (ceci doit être fait rapidement et est généralement géré à l’intérieur du gestionnaire d’interruptions.)" N’est-il pas fait avec un accès direct à la mémoire? - Siyuan Ren


Il y a beaucoup de détails "inférieurs".

Tout d'abord, considérez que le noyau a une liste de processus et, à tout moment, certains de ces processus sont en cours d'exécution, d'autres non. Le noyau permet à chaque processus en cours d’effectuer une partie du temps processeur, puis l’interrompt et passe à la suivante. S'il n'y a pas de processus exécutables, le noyau émettra probablement une instruction comme HLT à la CPU qui suspend la CPU jusqu'à une interruption matérielle.

Quelque part dans le serveur est un appel système cela dit "donne moi quelque chose à faire". Il y a deux grandes catégories de façons de procéder. Dans le cas d'Apache, il appelle accept sur une socket Apache a déjà ouvert, écoutant probablement sur le port 80. Le noyau maintient une file d'attente de tentatives de connexion, et ajoute à cette file d'attente chaque fois qu'un TCP SYN est reçu. La façon dont le noyau sait qu'un protocole 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 initiation de connexion. Si la file d'attente n'était pas vide, alors accept retourne juste 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 lancée ultérieurement, le processus reprend. C'est ce qu'on appelle le "blocage", car au processus l'appelant, accept()ressemble à une fonction qui ne retourne pas avant d'avoir un résultat, ce qui pourrait prendre du temps. Pendant ce temps, le processus ne peut rien faire d'autre.

Une fois que accept retourne, Apache sait que quelqu'un tente d'établir une connexion. Il appelle ensuite fourchette diviser le processus Apache en deux processus identiques. L'un de ces processus continue à traiter la requête HTTP, les autres appels accept à nouveau pour obtenir la prochaine connexion. Ainsi, il y a toujours un processus maître qui ne fait rien d'autre que d'appeler accept et générer des sous-processus, puis un sous-processus pour chaque demande.

Ceci est une simplification: il est possible de le faire avec des threads au lieu de processus, et il est également possible de fork au préalable, un processus de travail est prêt à recevoir une demande, ce qui réduit le temps système de démarrage. Selon la configuration d’Apache, il est possible que l’une ou l’autre soit

C'est la première grande catégorie de la façon de le faire, et elle s'appelle blocage des entrées-sorties parce que le système appelle comme accept et read et write qui fonctionnent sur les sockets vont suspendre le processus jusqu'à ce qu'ils aient quelque chose à retourner.

L’autre moyen de le faire est appelé non-bloquant ou événementiel ou E / S asynchrone. Ceci est implémenté avec des appels système comme select ou epoll. Celles-ci font la même chose: vous leur donnez une liste de sockets (ou en général, des descripteurs de fichiers) et ce que vous voulez en faire, ainsi que les blocs du noyau jusqu'à ce qu'ils soient prêts à faire l'une de ces choses.

Avec ce modèle, vous pourriez dire au noyau (avec epoll), "Dites-moi quand il y a une nouvelle connexion sur le port 80 ou de nouvelles données à lire sur l'une de ces 9471 autres connexions que j'ai ouvertes". epoll bloque jusqu'à ce que l'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 ne bloquez jamais, en partie parce que chaque fois que vous les appelez, epoll juste dit qu'ils sont prêts alors il n'y aurait aucune raison de bloquer, et aussi parce que lorsque vous ouvrez le socket ou le fichier que vous spécifiez que vous souhaitez les en mode non-bloquant, donc 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 utilisez ce modèle, et c'est une grande raison pour laquelle ils peuvent gérer autant de connexions que Apache sur du matériel similaire.


7
2017-11-12 19:38