Benchmark proxy
le 30 mars 2022, par
- 4 min de lecturePour utiliser le serveur JMAP de cyrus dans notre application de webmail, nous devons nous authentifier. Nous voyons qu’il n’y a pas d’autres mécanismes que de faire du basic auth HTTP. C’est un peu embêtant car cela oblige à envoyer les informations (utilisateur/mot de passe) de connexion pour chaque requête JMAP. Nous nous décidons alors à faire un petit proxy (comme ils l’indiquent dans l’issue) qui ajoutera les informations côté serveur.
C’est très simple de le faire en python puisque notre backend de connexion est en python/pyramid. La vérification de signature du JWT token, la lecture des informations dans la base Redis et le chiffrement/déchiffrement en AES est fait en 10 lignes de code. Le souci c’est que toutes les requêtes relatives aux mails (lister les mails, afficher un mail, etc.) passeront par ce proxy. C’est impactant en terme de sollicitation de nos serveurs. Nous faisons l’hypothèse qu’un proxy en Rust/hyper sera meilleur que notre backend python.
Alors nous implémentons un proxy en Rust. Il va juste aller chercher les credentials dans la base Redis, les décoder et les ajouter encodées en base64 dans le header Authorization
. Nous choisissons de le faire en asynchrone avec hyper pour qu’il soit le plus efficace possible.
A présent nous pouvons comparer notre proxy en python avec celui en Rust pour vérifier notre hypothèse. Pour cela nous faisons tourner un serveur nginx sur une machine, et sur une autre nous lançons notre proxy. L’injecteur ab tourne également sur la machine du proxy.
Ce test de performance nous intéresse car c’est typiquement un problème I/O bound (relatifs aux entrées sorties réseau) : le proxy reçoit des requêtes HTTP, va chercher (via le réseau encore) une valeur dans la base de données, et fait une requête vers le serveur nginx. Or nous savons que pour les problèmes CPU bound Rust est très performant. Qu’en est-il dans le cas de notre proxy ?
Nous faisons 7 tirs de 10000 requêtes:
- un tir de référence avec une concurrence de 1 (un utilisateur), directement sur nginx pour voir le temps de traitement des requêtes. Facile, il sert à 1ms
- un tir sur le proxy rust monothreadé (concurrence de 1) en mode debug
- un tir sur le proxy rust en compilation optimisée (nous avions oublié dans le tir précédent de faire un build optimisé avec l’option
--release
) - un tir sur le proxy rust en multithreadé (un thread par coeur)
- un tir sur le proxy python (concurrence de 1)
- un tir sur le proxy monothreadé rust avec une concurrence de 8 (8 utilisateurs en parallèle)
- un tir sur le proxy python avec une concurrence de 8
Voici les résultats obtenus :
Ce que nous voyons :
- dans les mêmes conditions (monothreadé, concurrence de 1) rust est 4,2 fois plus efficace que python
- rust en compilation non-optimisée est 2,6 fois moins efficace (comparativement à la version optimisée)
- la version multithreadée (p8t) fait à peine mieux que la version monothreadée
- avec une concurrence de 8 les performances de python s’effondrent. C’est probablement lié au fait que notre serveur est synchrone, il ne peut pas paralléliser les requêtes
- résultat que nous avons du mal à expliquer : rust fait mieux avec 8 utilisateurs parallèles qu’avec un seul
Ok c’est très fort pour rust. Cela dit la comparaison n’est pas tout à fait juste :
- nous vérifions la signature du JWT en SHA-512 donc il y a aussi de la CPU dans ce calcul (sans doute fait avec binding C pour python)
- nous décodons les crédentials en AES-256 ce qui est aussi de la crypto qui utilise la CPU (également avec un binding C pour python)
- le serveur python n’est pas asynchrone alors que le proxy rust l’est
Alors testons un pur reverse proxy HTTP asynchrone en monothreadé. Nous récupérons ce proxy asyncio python, et nous modifions le code de notre proxy pour qu’il ne fasse que relayer la requête vers le backend (juste la partie hyper-reverse-proxy).
Nous faisons plusieurs tirs de 100K requêtes. Voici les résultats:
Nous constatons que le proxy rust est toujours meilleur alors que nous sommes dans des situations comparables. Il ajoute 0,5ms au temps de réponse de nginx. Le proxy python répond très bien en ajoutant 1ms, mais c’est deux fois plus.
Conclusion, même sur des performances I/0 bound rust est quand même bien plus efficace que python. Nous avons déployé notre proxy en production. Notre proxy a également été référencé sur le site de JMAP.
Migration de dovecot vers cyrus
le 17 mars 2022, par
- 7 min de lectureAprès avoir fait tourner un serveur de mail IMAP dovecot et SMTP postfix, nous voulions ajouter des serveurs de calendrier et de contacts pour Iroco. Suite à l’étude comparative des langages de programmation, nous cherchons alors des serveurs qui soient si possible écrits en C/C++/Rust. Cette page de wikipedia donne un bon aperçu des différentes possibilités… et en même temps côté serveur on voit qu’il y a des serveurs en Java, en Objective-C, mais aucun en Rust et un seul en C : Cyrus.
Une nouvelle technologie d'appel système asynchrone pour les Entrées/Sorties
le 2 mars 2022, par
- 3 min de lectureAlors que la plupart des serveurs sous Linux utilisent le service epoll
pour gérer les E/S asynchrones, une nouvelle technologie est en train d’émerger et promet de se développer dans les années à venir : io_uring
.
Quelques publications de référence sur le numérique responsable
le 24 novembre 2021, par
- 1 min de lectureLe sujet du numérique responsable a pris de l’ampleur depuis quelques années et les publications qui en abordent l’un ou l’autre des aspects se multiplient. Si le sujet vous intéresse mais que vous ne savez pas par où commencer, voici quelques suggestions de lecture qui vous permettront d’entrer progressivement dans le bain :
- La synthèse de l’étude de GreenIT.fr sur l’empreinte environnementale du numérique mondial condense en une dizaine de pages accessibles l’essentiel des informations sur les impacts du secteur numérique, sur son évolution plausible d’ici 2025 et sur les bonnes pratiques à adopter pour limiter son impact.
- Le résumé pour les décideurs du rapport “Déployer la sobriété numérique” du Shift Project résume en quelques pages les grands enjeux du numérique responsable : évaluer la pertinence de la digitalisation, maîtriser les usages du numérique, penser et déployer la sobriété. Si le sujet vous passionne, rien ne vous empêche de lire l’intégralité du rapport.
- Pour un regard un peu plus interdisciplinaire sur le numérique et les usages que nous en faisons, nous vous conseillons les publications de Gauthier Roussilhe. Pourquoi ne pas commencer par Situer le numérique, qui introduit et met en perspective avec pédagogie les enjeux environnementaux du numérique ?
Benchmark vuejs vs. svelte (3/3)
le 20 octobre 2021, par
- 3 min de lectureLors de la présentation de nos résultats sur le benchmark vuejs/react au groupe de travail Boavizta, nous avons eu ces retours parmi d’autres :