Un journal précédent vient de lancer un taptempo du web. Le but est d'évaluer des technos quand il s'agit de faire un backend qui ne fait qu'envoyer une redirection 302 (cf le journal en dessous pour les détails).
La vitesse est mesuré par ab en local, wrk a aussi été proposé. L'empreinte mémoire est mesuré avec "ps aux" pour avoir le VSZ et le RSS.
On a pour l'instant 9k requêtes/s et 8 Mo en Java, 23k requêtes/s et 350Ko en Rust, 19k requêtes/s en Haskell. Bien sûr il faudrait lancer ces tests sur une même machine pour être fairplay.
Journal d'origine : https://linuxfr.org/users/spacefox/journaux/java-presque-9-000-requetes-par-seconde-avec-8-mo-de-ram
# En Python (Flask)
Posté par gUI (Mastodon) . Évalué à 4.
Bon, histoire de jouer j'ai lancé sur mon ordi portable du boulot le script suivant en Python. Fait en 2mn chrono, sans aucune recherche d'optimiser quoi que ce soit. Le CPU est un Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz .
Voici la ligne
ps aux
:Et le résultat de
ab
:Je vous laisse interpréter tout ça, j'ai pas trop suivi l'ensemble des débats du journal original :)
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: En Python (Flask)
Posté par Yth (Mastodon) . Évalué à 6.
Alors pour faire suite à mon commentaire originel que vous trouverez avec le code python en Bottle ici :
https://linuxfr.org/users/spacefox/journaux/java-presque-9-000-requetes-par-seconde-avec-8-mo-de-ram#comment-1893297
Rappel des épisodes précédents : le benchmark avec ab donne 3400 req/s en fournissant les images dans la réponse, et seulement 2800 req/s avec la redirection 302, avec 21Mo de RAM utilisée.
En utilisant le serveur gunicorn (simplement en mettant
server="gunicorn", workers=5
dans l'appel àbottle.run()
) on monte à 14000 req/s, la machine ayant 4 cœurs, augmenter le nombre de workers au delà de 5 ne fait absolument rien gagner. Mais là on est à 30Mo de RAM pour le master, et 21Mo de RAM pour chacun des 5 workers. Rapide mais on le paye !J'ai tenté de mettre l'application bottle derrière apache et le mod_wsgi (processes=5 threads=2), on est à 12000 req/s, les processus mod_wsgi font 23Mo de RAM chacun, on est quasiment à la vitesse et aux ressources de gunicorn mais avec le reste des possibilités d'apache, si on en a besoin.
Et puis j'ai poussé un petit peu, tester les différents serveurs disponibles comme backend de bottle, il y en a plein.
Et je suis tombé sur bjoern, qui utilise la libev, bibliothèque C de gestion d'évènements, très - très - rapide.
On monte à 17000 req/s, en monothread et 20Mo de RAM.
C'est assez bluffant par rapport à toutes les autres solutions, surtout par rapport aux 3400 du serveur par défaut !
Mais bon, en fait, pourquoi pas lancer l'application bjoern 5 fois et utiliser un load-balancer devant ?
lighttpd fait ça très bien et on est à 13000 req/s, honorable, mais sans intérêt.
Alors on va utiliser un vrai load-balancer : haproxy !
Et donc 5 backend appli standalone avec bjoern, un haproxy en round-robin devant, on passe à 19500 req/s !
On a le même score avec 4 backend, la machine a 4 cœurs, fait tourner haproxy et aussi l'outil de benchmark, on sature sans surcharger le nombre de backend.
Si on descends à 2 backend, on monte à 19700 req/s, à 3 backend on est à 19800 req/s.
On s'y attends un peu : 5 processus qui bossent (3 backends bottle/bjoern, haproxy, et ab pour les tests) sur 4 cœurs c'est en général ce qui optimise le plus, mais c'est assez marginal.
Bien sûr, là on est à 3*20Mo+8Mo = 68Mo.
En bref haproxy ça déchire, on le savait déjà, on le constate encore, 8Mo de RSS, c'est tout mini.
Et le serveur WSGI bjoern est très impressionnant dans l'écosystème WSGI.
Et on descends pas en dessous de 20Mo de RAM pour un processus Python.
Et le Bottle.redirect() est plus lent, avec 3*bjoern+haproxy on est à 15000 req/s, c'est naze.
Conclusion, fournir le fichier directement et ne pas faire de redirection 302 (de toute façon, derrière, côté navigateur, on fait deux requêtes, c'est atroce), utiliser bjoern en server WSGI, et si on vaut load-balancer entre plusieurs serveurs, dégainer haproxy.
Pour info le /etc/haproxy/haproxy.cfg utilisé est le suivant (les timeout servent pas dans notre cas, mais haproxy geint si on les met pas) :
Et le code final bottle, avec exactement deux dépendances python : bottle et bjoern
# nginx / openresty
Posté par Damien Thébault . Évalué à 3. Dernière modification le 15 juin 2022 à 13:31.
Avec nginx / openresty (il faut openresty pour pouvoir générer la valeur aléatoire avec la commande set_random)
Commande:
openresty -p "$PWD" -c ./nginx.conf
ps aux:
Résultat, sur un i7-4900MQ 4 cœurs 2.8GHz
À noter que le nombre de requètes/s dépend de l'ordinateur utilisé. Et aussi que "ab" est mono-threadé et est donc limité en performances (
htstress -n 200000 -c 10 -t 8
retourne 85595 requètes/s)[^] # Re: nginx / openresty
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
et wrk ?
"La première sécurité est la liberté"
# re- python server.http
Posté par flagos . Évalué à 3. Dernière modification le 15 juin 2022 à 16:32.
Je reprends l’implémentation en python http.server que j'avais donne, mais cette fois-ci elle renvoit bien un 302 au lieu de servir un fichier, ce qui la rend éligible a ce petit jeu:
Ca me donne 8.4k requests/s pour 7.8 MB de ram.
[^] # Re: re- python server.http
Posté par flagos . Évalué à 3.
En relisant, le self.path = 'index.html' ne sert a rien. On va peut etre gratter 0.1 MB de ram en l'enlevant :-)
[^] # Re: re- python server.http
Posté par gUI (Mastodon) . Évalué à 3.
Tu veux que je le vire ? Si qqu'un les compile tous ça va lui faciliter la tâche.
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: re- python server.http
Posté par flagos . Évalué à 2.
S'il te plait.
[^] # Re: re- python server.http
Posté par gUI (Mastodon) . Évalué à 3. Dernière modification le 15 juin 2022 à 16:33.
Corrigé, merci.
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
# OCaml (avec cohttp)
Posté par chimrod (site web personnel) . Évalué à 2.
Et voici une version en OCaml, j’ai utilisé cohttp qui est une librairie bas-niveau pour construire des requêtes client/serveur.
La sortie ps :
$ ps aux | grep tempo
sebasti+ 23319 0.8 0.4 119996 16464 pts/2 Sl+ 13:49 0:03 _build/default/tempo.exe
et le résultat du bench :
# Julia
Posté par abriotde (site web personnel, Mastodon) . Évalué à 2.
C'est un langage réputé performant. Par contre il se "compile" au premier appel alors j'ai fais un premier appel avant le test.
Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.