Il n'y a pas de solution miracle
En pratique cela dépend ...
tl; dr - solution facile, utilisez nginx ...
Blocage:
Par exemple, Apache utilise par défaut un schéma de blocage dans lequel le processus est bifurqué pour chaque connexion. Cela signifie que chaque connexion a besoin de son propre espace mémoire et la quantité de surcharge de changement de contexte augmente davantage à mesure que le nombre de connexions augmente. Mais l'avantage est qu'une fois la connexion fermée, le contexte peut être supprimé et toute / toute la mémoire peut être facilement récupérée.
Une approche multithread serait similaire dans la mesure où la surcharge de la commutation de contexte augmente avec le nombre de connexions, mais peut être plus efficace en mémoire dans un contexte partagé. Le problème avec une telle approche est qu'il est difficile de gérer la mémoire partagée d'une manière sûre. Les approches pour surmonter les problèmes de synchronisation de la mémoire incluent souvent leur propre surcharge, par exemple le verrouillage peut geler le thread principal sur les charges gourmandes en CPU, et l'utilisation de types immuables ajoute beaucoup de copie inutile de données.
AFAIK, l'utilisation d'une approche multi-processus sur un serveur HTTP bloquant est généralement préférée car il est plus sûr / plus simple de gérer / récupérer la mémoire d'une manière sûre. La récupération de place devient un non-problème lorsque la récupération de mémoire est aussi simple que l'arrêt d'un processus. Pour les processus de longue durée (c'est-à-dire un démon), cette caractéristique est particulièrement importante.
Alors que les frais généraux de changement de contexte peuvent sembler insignifiants avec un petit nombre de travailleurs, les inconvénients deviennent plus pertinents à mesure que la charge augmente jusqu'à des centaines à des milliers de connexions simultanées. Au mieux, le changement de contexte met à l'échelle O (n) le nombre de travailleurs présents, mais en pratique, il est très probablement pire.
Lorsque les serveurs qui utilisent le blocage peuvent ne pas être le choix idéal pour les charges lourdes d'E / S, ils sont idéaux pour les travaux gourmands en ressources processeur et le passage des messages est limité à un minimum.
Non bloquant:
Le non-blocage serait quelque chose comme Node.js ou nginx. Celles-ci sont particulièrement connues pour évoluer vers un nombre beaucoup plus élevé de connexions par nœud sous une charge gourmande en E / S. Fondamentalement, une fois que les utilisateurs ont atteint la limite supérieure de ce que les serveurs basés sur les threads / processus pouvaient gérer, ils ont commencé à explorer d'autres options. Ceci est autrement connu comme le problème C10K (c'est-à-dire la capacité à gérer 10 000 connexions simultanées).
Les serveurs asynchrones non bloquants partagent généralement beaucoup de caractéristiques avec une approche multi-thread avec verrouillage en ce sens que vous devez faire attention à éviter les charges gourmandes en CPU car vous ne voulez pas surcharger le thread principal. L'avantage est que la surcharge engendrée par le changement de contexte est essentiellement éliminée et avec le passage d'un seul message de contexte devient un non-problème.
Bien que cela puisse ne pas fonctionner pour de nombreux protocoles de mise en réseau, la nature sans état HTTP fonctionne particulièrement bien pour les architectures non bloquantes. En utilisant la combinaison d'un proxy inverse et de plusieurs serveurs HTTP non bloquants, il est possible d'identifier et d'acheminer autour des nœuds soumis à une forte charge.
Même sur un serveur qui n'a qu'un seul nœud, il est très courant que la configuration inclue un serveur par cœur de processeur pour maximiser le débit.
Tous les deux:
Le cas d'utilisation «idéal» serait une combinaison des deux. Un proxy inverse en façade dédié au routage des requêtes en haut, puis un mix de serveurs bloquants et non bloquants. Non bloquant pour les tâches IO comme la diffusion de contenu statique, le contenu de cache, le contenu html. Blocage pour les tâches gourmandes en CPU telles que l'encodage d'images / vidéos, la diffusion de contenu, la compression de nombres, les écritures de base de données, etc.
Dans ton cas:
Si vous ne faites que vérifier les en-têtes mais ne traitez pas réellement les demandes, ce que vous décrivez essentiellement est un proxy inverse. Dans un tel cas, j'opterais définitivement pour une approche asynchrone.
Je suggère de consulter la documentation du proxy inverse intégré nginx .
De côté:
J'ai lu l'article du lien que vous avez fourni et il est logique que l'async soit un mauvais choix pour leur implémentation particulière. Le problème peut être résumé en une seule déclaration.
A constaté que lors du basculement entre les clients, le code d'enregistrement et de restauration des valeurs / état était difficile
Ils construisaient une plate-forme d'État. Dans un tel cas, une approche asynchrone signifierait que vous devriez constamment sauvegarder / charger l'état chaque fois que le contexte change (c'est-à-dire lorsqu'un événement se déclenche). De plus, du côté SMTP, ils font beaucoup de travail gourmand en CPU.
On dirait qu'ils avaient une assez mauvaise compréhension de l'async et, par conséquent, ont fait beaucoup de mauvaises hypothèses.