2 points par GN⁺ 2025-07-07 | 1 commentaires | Partager sur WhatsApp
  • Avec la programmation CGI, il est possible de traiter plus de 200 millions de requêtes web par jour
  • Les récents progrès des performances matérielles ont fortement réduit les inconvénients de l’approche CGI
  • Un programme CGI utilisant Go et SQLite a montré d’excellentes performances sur un CPU à 16 threads
  • CGI offre une architecture particulièrement adaptée à l’exploitation de plusieurs cœurs CPU
  • Avec les technologies modernes, les anciennes méthodes de développement d’applications web redeviennent tout à fait pratiques

Le passé et le présent de CGI

  • À la fin des années 1990, l’auteur a commencé le développement web avec CGI et utilisait alors des systèmes comme NewsPro
  • CGI répétait l’exécution puis l’arrêt d’un nouveau processus à chaque requête web, ce qui entraînait une forte surcharge
  • C’est pour cette raison que des technologies alternatives plus efficaces, comme PHP et FastCGI, ont été développées

Les progrès des performances matérielles

  • Au cours des vingt dernières années, la vitesse et les performances des ordinateurs ont fortement augmenté
  • En 2020, l’auteur a redécouvert l’aspect pratique de l’exécution par processus en utilisant des outils développés en Go et en Rust, comme ripgrep

Les avantages d’une approche CGI moderne

  • En implémentant CGI dans des langages rapides à l’exécution comme Go et Rust, la plupart des défauts de l’ancien CGI disparaissent
  • Un programme CGI fonctionne comme un processus distinct par requête, ce qui l’optimise pour l’utilisation des CPU multicœurs
    • Par exemple, dans un environnement à 16 threads, il a été constaté qu’il était possible de traiter plus de 2 400 requêtes par seconde, soit plus de 200 millions par jour
    • Les grands serveurs peuvent offrir plus de 384 threads CPU

Un éclairage sur la culture du développement

  • Aujourd’hui, avec l’adoption de langages comme Go et Rust, l’approche CGI des années 1990 peut retrouver de la pertinence
  • Cela dit, elle ne convient toujours pas à tous les environnements et n’est pas recommandée comme approche dominante
  • Le point important est qu’il a été démontré expérimentalement qu’à l’heure actuelle, CGI n’est plus une solution aussi inefficace qu’autrefois

Conclusion

  • Grâce au matériel moderne et au support de langages rapides, la programmation CGI affiche des performances incomparables avec celles du passé
  • C’est un exemple qui exploite au maximum les avantages du multiprocessus et qui offre des pistes de réflexion intéressantes aux développeurs web

1 commentaires

 
GN⁺ 2025-07-07
Réactions sur Hacker News
  • De nos jours, même en Python, CGI donne une impression de performances tout à fait correcte
    Même si un script CGI consomme 400 millisecondes de CPU au démarrage, avec un serveur à 64 cœurs on peut traiter 160 requêtes par seconde, soit 14 millions de requêtes par jour et par serveur
    Autrement dit, même un trafic quotidien de l’ordre de la centaine de millions de requêtes (hors assets statiques) n’a pas pour goulot d’étranglement le démarrage des processus CGI
    Avant, je pensais que ce genre de technologie était « tellement stable qu’elle en devient ennuyeuse », donc naturellement toujours présente dans la bibliothèque standard de Python, mais les mainteneurs Python actuels semblent au contraire moins favorables à la stabilité et à la rétrocompatibilité
    Résultat, les modules « trop ennuyeux et trop stables » sont retirés de la bibliothèque standard, et le module cgi a effectivement été supprimé en version 3.13
    C’est sans doute lié à mon habitude d’utiliser Python pour le prototypage depuis presque 25 ans, mais aujourd’hui je le regrette un peu
    Je me sens tiraillé entre JS et Lua

    • Le lien vers l’explication officielle du retrait de cgi est PEP 594 cgi
      Ce lien renvoie aussi à PEP 206, rédigé en 2000 (il y a 25 ans), où l’on expliquait déjà que « le package cgi est mal conçu et difficile à faire évoluer »
      Le dépôt jackrosenthal/legacy-cgi propose un drop-in replacement du module de la bibliothèque standard

    • Les développeurs Python n’ont retiré que le module nommé cgi
      L’implémentation de scripts CGI reste prise en charge par CGIHTTPRequestHandler du module http.server
      Il faut aussi rappeler que le module cgi ne contenait à l’origine que quelques fonctions pour parser les données de formulaires HTML

    • Je comprends qu’on critique la suppression du module cgi de la bibliothèque standard Python, mais le JS souvent cité en alternative n’a carrément pas de bibliothèque standard
      Et Lua non plus n’a pas de module CGI dans sa stdlib

    • Personnellement, je préfère PHP ou JS
      Dans ce genre de cas, on a du JIT prêt à l’emploi dans la boîte, ce qui est pratique
      J’utilise Python depuis la version 1.6, mais principalement pour le scripting système
      À l’époque, avec Tcl intégré à Apache ou IIS via des modules, j’ai connu cette boucle sans fin où l’on réécrivait constamment les modules en C (1999~2003)

    • Si un script CGI consomme 400 millisecondes de CPU, alors le temps de réponse de cet endpoint sera lui aussi d’au moins cet ordre-là, avec un impact direct sur l’utilisabilité

  • Récemment, j’ai installé un binaire golang, rabbitmq, redis et MySQL sur un mini-serveur à 350 dollars, et il traite durablement 5 000 req/s sur la même machine
    Sur 24 heures, cela représente une capacité de 400 millions de requêtes
    Ça rappelle à quel point les outils gratuits d’aujourd’hui sont excellents
    Malgré ça, je trouve toujours le cloud beaucoup trop cher
    Bien sûr, la comparaison n’est pas strictement équivalente, mais j’ai beaucoup apprécié le fait de pouvoir développer et tuner directement sur un serveur dans mon sous-sol

    • Il existe des cas où une grosse pile de microservices basée sur Kubernetes rend le développement 10 fois plus lent
      Beaucoup de gens oublient qu’un serveur n’est pas une machine qui ne traite qu’une seule requête par seconde
      La réalité, c’est qu’on paie un overhead excessif juste parce que « Google le fait, donc il faut suivre »
      Moi aussi, je me dis que je devrais écrire un article sur l’architecture « monolithe modulaire », qui fonctionne bien pour notre équipe

    • J’ai envisagé d’héberger moi-même un side project à la maison, mais les risques sont importants : coupures de courant, indisponibilité de l’ISP, accès distant impossible, panne de disque dur, etc.
      Au final, si on tient compte de mon temps, le gain économique devient discutable
      Les services cloud bénéficient d’économies d’échelle, donc c’est en pratique un choix raisonnable

    • Sans forcément passer par le cloud, on peut aussi louer un serveur dédié chez un hébergeur
      Bien sûr, il existe des limites de bande passante et de trafic
      Si le cloud est dominant, c’est aussi parce que des VC ou des investisseurs détiennent des parts dans ces entreprises, ou à cause de la peur qu’« un trafic illimité puisse soudainement exploser »
      Les commerciaux du cloud savent très bien exploiter l’anxiété des investisseurs

    • On n’est pas obligé d’utiliser le cloud

    • Si le coût des VM est élevé en production, ce n’est pas forcément à cause de la puissance de calcul, mais parce qu’il faut d’énormes volumes de disque local
      On n’a pas besoin d’une grande capacité de calcul ; avec quatre disques de 20 To et un CPU correct, on peut déjà imaginer un service impressionnant
      Dans le cloud, il est presque impossible de trouver ce type de combinaison

  • Quand on a besoin d’accéder à une base de données depuis cgi-bin, c’est gênant de devoir recréer une connexion DB à chaque nouveau processus
    Si le code tourne en mémoire (avec fastcgi, par exemple), on ne gagne pas seulement sur le temps de démarrage : on peut aussi avoir un pool de connexions DB ou des connexions persistantes par thread

    • À grande échelle, le nombre de connexions DB devient énorme et finit par mettre la base sous pression
      On se retrouve à faire tourner beaucoup de processus pour des raisons du genre « python est monothread, donc plusieurs processus », puis « python est lent, donc encore plus de processus »
      Au bout du compte, il faut externaliser le shared connection pool hors des processus Python (avec pg bouncer, par exemple), puis faire divers réglages
      Et finalement, tout est devenu beaucoup plus simple quand on a réécrit le tout dans un langage plus discipliné, avec support du multithreading et de meilleures performances

    • C’est pour cela qu’au final CGI a évolué vers un modèle qui conserve des informations entre les requêtes, comme fastcgi

    • Traditionnellement, on lançait aussi un daemon indépendant jouant le rôle de proxy, et avec des sockets Unix les connexions sont bien plus efficaces qu’en TCP/IP

    • Quelqu’un suggère d’utiliser UDP

  • Pour moi, inetd, c’est CGI à l’état pur
    J’ai l’impression que ça rendait Internet beaucoup plus amusant
    C’était l’époque où je faisais tourner toutes sortes de scripts shell avec inetd, y compris du HTTP écrit uniquement en Bash
    Les vieux VPS et les laptops sans sauvegarde ni contrôle de version ont disparu, mais ce sont de bons souvenirs
    Le déploiement restait simple avec Makefile + scp, et les tests pouvaient s’écrire en Bash avec netcat et grep
    Franchement, on vit une belle époque

  • Voir une appli hello world plafonner à 2400 rps (requêtes par seconde) me donne l’impression que ce n’est pas terrible au regard du matériel actuel
    Le code n’est même pas devenu plus simple, donc je me demande vraiment au nom de quoi on sacrifie les performances

    • S’il n’y a pas besoin de dépasser 2000 rps, alors ce n’est pas un problème
      L’idée, c’est qu’il n’existe qu’un très petit nombre de sites qui ont réellement besoin d’un tel trafic

    • Numériquement, ce n’est pas énorme, mais en pratique c’est largement suffisant pour beaucoup d’environnements
      C’est même assez robuste pour encaisser le « hug of death » dont parlent souvent les développeurs HN, c’est-à-dire un pic soudain de trafic

  • Dans notre entreprise, on utilise encore un répertoire cgi-bin pour mettre rapidement en ligne de petites webapps internes
    Tant qu’on reste sur des usages simples, l’efficacité de développement est excellente
    Même en CGI, il n’est pas nécessaire de print soi-même du HTTP/1.0 ; on peut utiliser Python wsgiref.handlers.CGIHandler pour exécuter n’importe quelle appli WSGI comme script CGI
    Le code d’exemple Flask est aussi simple que ceci

     import wsgiref.handlers, flask
     app = flask.Flask(__name__)
     wsgiref.handlers.CGIHandler().run(app)
    

    En production, on exécute les scripts via le plugin CGI de uwsgi
    J’ai l’impression que c’est bien plus simple et plus flexible que de faire tourner mod_cgi dans Apache ou lighttpd
    Comme uwsgi s’exécute au niveau système, on peut aussi bénéficier de tout le hardening et du sandboxing de systemd, ce qui est un vrai avantage
    En plus, la gestion CGI de uwsgi permet de spécifier un interpréteur pour chaque type de fichier

     cgi = /cgi-bin=/webapps/cgi-bin/src
     cgi-allowed-ext = .py
     cgi-helper = .py=/webapps/cgi-bin/venv/bin/python3 # all dependencies go here
    

    Le délai avant le premier octet est de 250 à 350 ms, ce qui reste tout à fait acceptable pour notre usage
    Documentation uwsgi sur CGI

    • Merci pour l’astuce
      Le fait que wsgiref.handlers.CGIHandler ne soit toujours pas deprecated est une information utile
  • Fil connexe discuté hier : lien

  • Récemment, j’ai utilisé Apache pour un side project parce que la fonctionnalité .htaccess était pratique
    Il suffit de déposer un fichier .htaccess dans n’importe quel répertoire pour charger une configuration serveur supplémentaire à chaque requête individuelle
    Documentation officielle sur htaccess
    Autrefois, on recommandait d’éviter .htaccess pour des raisons de performance, à cause de l’overhead d’accès disque à chaque requête, et de fusionner autant que possible cela dans la configuration principale
    Mais aujourd’hui, avec les SSD et la RAM disponibles, même s’il y a bien une légère perte de performance, la plupart des CPU sont suffisamment puissants pour que cela reste négligeable dans la grande majorité des cas
    [Mon projet StaticPatch][https://github.com/StaticPatch/StaticPatch/tree/main] l’utilise déjà en production

    • Citation célèbre de Rasmus Lerdorf, le créateur de PHP
      « Je ne suis pas un vrai programmeur, je fais juste en sorte que ça marche et je passe à autre chose. Les vrais programmeurs disent : “il y a de grosses fuites mémoire, il faut corriger ça”. Moi, je redémarre juste apache toutes les 10 requêtes. »
      PHP a depuis parcouru un long chemin et a énormément progressé en surmontant ses erreurs de jeunesse
      On raconte aussi qu’il a dit : « PHP 8 est meilleur quand j’écris moins de code »

    • Je ne comprends pas pourquoi Apache ne surveille pas simplement le système de fichiers pour ne relire les fichiers qu’en cas de modification, au lieu d’imposer des accès disque inutiles à chaque requête
      Résultat : 99,99 % des requêtes HTTP sont ralenties pour rien

  • Ces derniers temps, je réfléchis à ce type d’architecture pour du prototypage rapide dans mon workflow
    Avec les langages à JIT, si on n’est pas en mode fastcgi, l’import devient un goulot d’étranglement
    Le serveur web h2o que j’ai utilisé moi-même a une configuration simple pour mruby et les handlers fast-cgi, ce qui le rend parfait pour du scripting local
    Documentation h2o fastcgi
    Autre avantage : cela sert aussi lorsqu’on veut permettre à des clients d’étendre un logiciel local en y ajoutant eux-mêmes du code personnalisé
    Par exemple, auparavant il fallait utiliser MCP pour les extensions, alors qu’aujourd’hui il suffit d’implémenter des requêtes structurées via CGI

    • Comme environnement pour utilisateurs finaux, l’idée de brancher un programme CGI derrière une façade MCP mérite d’être envisagée
      Un service MCP semble tout à fait pouvoir être implémenté en CGI lui aussi
      J’ai envie d’examiner la spécification de plus près

    • Je me demande si fastcgi ne fait pas disparaître presque tous les avantages propres à cgi

  • J’ai déjà utilisé directement la combinaison programmes en C + CGI
    À l’époque, on n’avait ni plus de 100 cœurs ni des quantités de RAM confortables, et pourtant ça tournait avec au plus 1 Go de mémoire
    Quand je repense à ce qu’on arrivait à faire alors, je suis persuadé qu’aujourd’hui ce serait bien plus facile

    • En 1995, Amazon utilisait des exécutables C++ en mode CGI
      Quand la montée en charge a commencé à nécessiter de la répartition de charge, cela est devenu plus difficile à faire évoluer, mais avant cela, ça fonctionnait plutôt bien
      À titre de référence, le front et le back-office étaient deux exécutables distincts