- Présentation d’une stratégie pour ajouter progressivement Rust à des serveurs non-Rust (JavaScript, Python, Java, etc.)
- L’objectif est d’identifier les fonctions critiques limitées par le CPU qui ne satisfont pas aux exigences de performance, puis de les remplacer par des implémentations en Rust
- La stratégie est divisée en niveaux d’adoption de Rust (Tier) : le Tier 0 n’utilise pas Rust, et le dernier Tier consiste à réécrire l’ensemble du serveur en Rust
Stratégie
Tier 0 : sans Rust
- Implémentation d’un endpoint de génération de QR code sur un serveur Node.js
- Performances de référence : 1464 requêtes par seconde, latence moyenne de 68 ms, latence p99 de 96 ms, taille moyenne de réponse de 1506 octets, mémoire 1353 MB
Tier 1 : outil CLI en Rust
- Réécriture de la fonction de génération de QR code en Rust, puis compilation en outil CLI
- Appel de l’outil CLI depuis le serveur hôte
- Performances par rapport à la référence : nombre de requêtes par seconde multiplié par 1,76, latence moyenne réduite à 0,57x, taille moyenne de réponse réduite à 0,52x, mémoire réduite à 0,92x
Tier 2 : module Wasm Rust
- Compilation de la fonction Rust en module Wasm, puis chargement et exécution via un runtime Wasm sur le serveur hôte
- Utilisation de
wasm-bindgen sur le serveur Node.js
- Performances par rapport à la référence : nombre de requêtes par seconde multiplié par 2,03, latence moyenne réduite à 0,50x
- Explication de la manière d’écrire manuellement des bindings Wasm (pour les utilisateurs d’autres langages)
Tier 3 : fonction native Rust
- Écriture de la fonction en Rust, compilation en code natif, puis chargement et exécution dans le runtime hôte
- Utilisation de
napi-rs pour Node.js
- Performances par rapport à la référence : nombre de requêtes par seconde multiplié par 3,75, latence moyenne réduite à 0,26x
Tier 4 : réécriture en Rust
- Réécriture complète du serveur hôte en Rust
- En pratique, il est plus réaliste de ne réécrire qu’une partie du serveur hôte
- Performances par rapport à la référence : nombre de requêtes par seconde multiplié par 4,93, latence moyenne réduite à 0,21x, mémoire réduite à 0,01x (13 MB utilisés)
Conclusion
- Toutes les stratégies sont intéressantes, mais le Tier 3 est le plus efficace
- S’il est possible d’utiliser une bibliothèque prête à l’emploi de génération de bindings, écrire des fonctions natives en Rust est simple et a un impact important sur les performances
4 commentaires
Oh........ à force de faire un peu de tout comme un homme à tout faire, j’en suis venu à utiliser un peu les deux, et c’est une information vraiment très utile.
Je m’intéresse à Rust en ce moment. C’est un article intéressant.
C’est un très bon article. Voilà un bon exemple d’une utilisation pertinente de Rust.
On dirait bien que Rust gagne clairement en popularité dans des domaines qu’on résolvait auparavant en C/C++.