- Il est confirmé par expérimentation que les programmes CGI, largement utilisés aux débuts du Web, peuvent encore offrir de hautes performances sur du matériel moderne
- Le CGI traite les requêtes par processus, ce qui permet une gestion automatique de la mémoire et offre l’avantage d’un déploiement simple
- Les résultats des benchmarks démontrent qu’un serveur ordinaire avec un CPU à 16 threads peut traiter plus de 2 400 requêtes par seconde, soit plus de 200 millions par jour
- Le code d’exemple guestbook.cgi, écrit en Go et SQLite, ainsi que le Dockerfile, sont publiés en open source
- Bien que le CGI ne soit plus couramment utilisé aujourd’hui, l’article montre qu’il peut rester une alternative pratique et moderne
Programmes CGI et principe de fonctionnement
- Au début des années 2000, les programmes CGI (Common Gateway Interface) constituaient la principale méthode pour créer des sites web dynamiques
- Ils étaient le plus souvent écrits en Perl ou en C, le C étant parfois choisi pour améliorer les performances
- Le concept du CGI est simple mais puissant
- Le serveur web place dans des variables d’environnement les métadonnées de la requête (en-têtes HTTP, requête, etc.)
- Il crée un processus distinct pour exécuter le programme CGI
- Il transmet le corps de la requête via
stdin
- Il capture le
stdout du programme comme réponse HTTP
- Il envoie la sortie
stderr dans les logs d’erreur du serveur
- Une fois la requête terminée, le processus s’arrête et les descripteurs de fichiers ainsi que la mémoire sont libérés automatiquement
- Du point de vue des développeurs, déployer une nouvelle version était aussi extrêmement simple : il suffisait de copier le fichier dans le répertoire
cgi-bin/
Hug of death (explosion du trafic)
- Au début des années 2000, la plupart des serveurs web fonctionnaient couramment avec 1 à 2 CPU et 1 à 4 Go de mémoire
- En raison de l’architecture du serveur web Apache, qui crée un processus
httpd par connexion via fork, les besoins en mémoire augmentaient avec le nombre de connexions
- Il était difficile de dépasser 100 connexions simultanées, et un simple lien depuis un site populaire suffisait souvent à surcharger le serveur
- ( Slashdot Effect : lorsqu’un lien apparaissait sur le très populaire Slashdot à l’époque, le trafic affluait d’un coup. C’est comparable aujourd’hui à une mise en avant en tête de Hacker News)
Le CGI dans un environnement serveur moderne
- Il existe désormais des serveurs dotés de 384 threads CPU, et même de petites VM peuvent proposer 16 CPU
- Les performances CPU et mémoire ont fortement progressé
- Comme les programmes CGI reposent sur des processus distincts, ils peuvent exploiter naturellement le multicœur
- C’est pour cette raison qu’un benchmark a été mené afin de mesurer directement la rapidité des programmes CGI sur du matériel moderne
- L’expérience a été réalisée sur un serveur AMD 3700X (16 threads)
Principaux résultats des benchmarks
- Un programme CGI simple a été testé à la fois avec Apache et avec un serveur Go
net/http
-
Description du programme guestbook.cgi
- L’outil de génération de charge HTTP
plow a été utilisé pour envoyer 100 000 requêtes avec 16 connexions
- Même sur du matériel ordinaire, il est possible de traiter plus de 2 400 requêtes par seconde, soit plus de 200 millions de requêtes par jour
- Le CGI n’est plus dominant aujourd’hui, mais il reste utilisable en production réelle
-
Benchmark d’écriture dans l’environnement Apache
- Traitement d’environ 2 468 requêtes par seconde, avec une latence moyenne de 6,47 ms
- 100 000 requêtes POST ont été traitées en seulement 40,5 secondes
- La plupart des requêtes ont reçu une réponse en 7 ms, et une infime minorité seulement a dépassé 100 ms
- Cela démontre en pratique d’excellentes performances en écriture
-
Benchmark de lecture dans l’environnement Apache
- Traitement d’environ 1 959 requêtes par seconde, avec une latence moyenne de 8,16 ms
- 100 000 requêtes GET ont été traitées en 51 secondes
- Plus de la moitié des requêtes ont été servies en moins de 8 ms, et la latence maximale n’a atteint que 31 ms
- Les performances en lecture sont elles aussi largement satisfaisantes
-
Benchmark d’écriture dans l’environnement Go net/http
- Traitement d’environ 2 742 requêtes par seconde, avec une latence moyenne de 5,83 ms
- 100 000 requêtes POST ont été traitées en 36,4 secondes
- Le débit atteint en moyenne 2 742 RPS, avec une latence moyenne de 5,8 ms, soit de meilleurs chiffres qu’Apache
- Plus de 95 % des requêtes ont été traitées en moins de 6 ms
- Le CGI dans l’environnement Go offre lui aussi des performances suffisantes pour un usage réel
-
Benchmark de lecture dans l’environnement Go net/http
- Traitement d’environ 2 469 requêtes par seconde, avec une latence moyenne de 6,47 ms
- 100 000 requêtes GET ont été traitées en 40,4 secondes
- La plupart des requêtes peuvent être servies en moins de 7 ms
- Le débit en lecture et le temps de réponse sont comparables ou supérieurs à ceux d’Apache
Conclusion et liens
- Les programmes CGI conservent des atouts sur du matériel récent : concurrence très élevée, déploiement simple et libération automatique des ressources par le système d’exploitation
- Comparés aux frameworks modernes, ils restent extrêmement simples, mais peuvent encore être utilisés en production pour des services d’une certaine taille
- L’exemple de livre d’or et les données de benchmark sont publiés sur le GitHub ci-dessous
https://github.com/Jacob2161/cgi-bin
4 commentaires
Oh là là… On va se remettre à utiliser du CGI ?? haha
Waouh… ça date de quand, le CGI…
Il y a du nouveau mis à jour à la date du 7/7.
Serving a half billion requests per day with Rust + CGI
500 millions de requêtes, quand même...
Avis Hacker News
Souvenir d’environnements des années 1990 où des programmes CGI écrits en C étaient vraiment très rapides, tout en reconnaissant que leur défaut était de générer beaucoup d’erreurs ; les programmes modernes en Go ou dans des langages comme Nim mentionnés dans l’article donnent aussi une impression de grande vitesse et de faible latence en localhost tant qu’ils ne se connectent pas à une base de données, un peu comme utiliser
fork & execdans un utilitaire CLI ; comparé à la latence réseau, le coût était presque négligeableMention aussi d’une culture qui pousse facilement à devenir dépendant d’une technologie précise ; par exemple, une fois habitué à des langages au coût de démarrage élevé comme l’interpréteur Python, on finit par considérer qu’un modèle multishot ou persistant est nécessaire
Le modèle one-shot des débuts de HTTP venait à l’origine du manque de mémoire des serveurs FTP, qui ne pouvaient pas conserver longtemps des centaines de sessions de connexion inactives
Mention de la possibilité d’une excellente conception système en combinant le pre-forking en CGI (qui peut masquer la latence) et un langage sûr comme Rust ; la terminaison TLS peut être gérée dans un serveur web multithreadé, ou dans une couche comme CloudFront, ce qui est présenté comme très pratique
fork()et par la volonté d’éviter les dangers du C lors de l’essor de Java ; on peut maintenant revenir à la simplicitéTémoignage d’un développeur ayant commencé à l’époque du CGI et ayant gardé une forte aversion pour l’idée de lancer des sous-processus de courte durée
Explication du fait que PHP et FastCGI ont été créés pour échapper au problème de performance consistant à lancer un nouveau processus à chaque requête web
Avec les progrès récents du matériel, il s’est rendu compte que le coût de démarrage d’un processus n’est en réalité pas un si gros problème
Ce benchmark peut traiter 2 000 requêtes par seconde, et même quelques centaines suffisent dans un environnement moderne où il est facile de scaler sur plusieurs instances
Accord avec l’idée décrivant AWS Lambda comme une renaissance du modèle CGI, comparaison jugée assez juste
Si les scripts CGI avaient été déployés sous forme de binaires C à liaison statique, en faisant même attention à leur taille, la déception aurait sans doute été moindre
Le CGI n’était ni financièrement ni techniquement très coûteux dans des environnements à faible charge
Avant l’arrivée de Go, dans les années 2000, écrire des programmes CGI en C/C++ était difficile à la fois en matière de sûreté et de développement
Aujourd’hui, on vit à une époque où des serveurs disposent de 384 threads CPU, et même de petites VM peuvent avoir 16 CPU
Sur ce type de matériel, développer avec Kestrel permettrait sans difficulté de traiter des milliers de milliards de requêtes par jour
Il serait possible d’offrir une expérience de développement proche de PHP grâce à l’opérateur d’interpolation de chaînes
Avec LINQ et
String.Join(), on peut facilement templatiser des tableaux HTML et des éléments imbriquésLa vraie difficulté est surtout de savoir éviter les pièges de l’écosystème comme MVC/Blazor/EF
Il est même possible d’exécuter tout le programme comme un seul fichier de niveau supérieur depuis le CLI, mais sans connaître le mot-clé « Minimal APIs », on risque facilement de se perdre dans un labyrinthe de mauvaise documentation
L’avantage du CGI est qu’en environnement multitenant, il n’est pas nécessaire de reconstruire des primitives d’isolation
rlimitcgroup, il est possible d’allouer équitablement par tenant l’usage mémoire, CPU, IO disque/réseauGrâce aux scripts CGI, perl a été optimisé pour un démarrage rapide
En exécutant la commande
time perl -e '', on constate que perl démarre en 5 ms, contre 33 ms pour python3 et 77 ms pour ruby#!/bin/tcc -runsont 1,3 fois plus rapides que perlgetlinen’était pas standard, et où l’on écrivait des bibliothèques C tierces de plusieurs centaines à plusieurs milliers de lignesEn utilisant apache tomcat 11, il suffit d’uploader via ssh un fichier .jsp ou une application java servlet complète (.war) pour que cela fonctionne directement
Les performances maximales sont obtenues grâce à une JVM partagée unique
Les pools de connexions DB, caches, etc. peuvent aussi être partagés entre applications
Expérience jugée vraiment impressionnante
Tout dépend toutefois des usages réels
Excellent pour les services à grande échelle, mais si 50 petites applications ne traitent chacune que quelques centaines de requêtes par jour, le surcoût mémoire de Tomcat est bien trop élevé par rapport à Apache/Nginx avec scripts CGI
Nostalgie de l’époque où déployer consistait simplement à copier un fichier
Regret de voir le processus de déploiement devenir si complexe
Partage d’expérience d’une utilisation toujours très agréable de Jetty pour des webapps backend
Impression que la stack Tomcat/Jakarta EE/JSP est étonnamment solide
On peut mélanger HTML et code comme en PHP, ou bien utiliser des routes Java pures
Support des WebSockets et modèle single-process multithread, avec des atouts pour la communication temps réel
Si nécessaire, on peut partager des données par requête, tandis que le code JSP reste limité par défaut au scope de la requête
Le déploiement est vraiment simple : il suffit d’envoyer un nouveau fichier dans le répertoire webapps, et Tomcat charge automatiquement la nouvelle application tout en déchargeant l’ancienne
Inconvénient : les fuites de classloader peuvent empêcher le garbage collection, destin classique du modèle single-process
Création d’un outil de visualisation des requêtes apache : ibrahimdiallo.com/reqvis
Il y avait des doutes sur la tendance actuelle vers des architectures complexes ; avec un bon matériel, il est peut-être en réalité possible de continuer à utiliser des technologies plus anciennes
À la question de concevoir un système diffusant des informations boursières en temps réel à des millions de personnes, la première idée aurait été une structure de streaming complexe avec Kafka, pubsub, etc., mais la possibilité d’une approche simple basée sur des fichiers statiques sur le serveur a fini par être envisagée
Curiosité sur le coût réel d’exploitation d’une telle approche
Mise en avant de la ressemblance avec une architecture serverless, mais en beaucoup plus simple et moins cher
Regret qu’au lieu de reconsidérer ces structures traditionnelles, on ait simplement inventé un nouveau paradigme appelé « serverless functions »
Bon, pour CGI passe encore, mais la réaction à JSP est surprenante lol
Est-ce que JSP est déjà devenu à ce point une relique de l’Antiquité ?