Limitation de débit et Throttling en Rust : Maîtriser les flux de données

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Quand Rust rencontre la surcharge : pourquoi votre service « plante » ?

\n\n

Imaginez que vous ayez écrit en Rust un service idéal pour les fortes charges. Il vole, utilise tous les avantages des abstractions à coût zéro et de la propriété de la mémoire. Mais voilà le problème — un client « gourmand » arrive et commence à bombarder votre serveur de milliers de requêtes par seconde. Que se passe-t-il ? La base de données plante ? La file d'attente s'étouffe ? Ou, pire encore, vous êtes banni par l'API externe que vous utilisez vous-même ?

\n\n

En Rust, comme dans tout autre langage, on ne peut pas se passer de rate limiting (limitation de débit) et de throttling (étranglement). Ce n'est pas simplement une « bonne pratique » — c'est une question de survie de votre application en production. Mais Rust a une particularité : nous aimons tout faire efficacement et à partir de zéro. Cependant, il ne sera pas nécessaire de réinventer la roue — nous avons de puissants crates (bibliothèques) et des motifs élégants.

\n\n

Dans cet article, nous verrons comment implémenter correctement la limitation des requêtes en Rust, en utilisant à la fois des algorithmes classiques (Token Bucket) et des approches asynchrones modernes. Vous apprendrez à protéger votre API contre les attaques DDoS, à ne pas dépasser les limites des services externes et à écrire votre propre throttler qui sera plus rapide qu'en Go ou Python.

\n\n

Rate Limiting vs Throttling : quelle est la différence ?

\n\n

Avant de plonger dans le code, clarifions une fois pour toutes les termes. On les confond souvent, mais la différence est cruciale.

\n\n
    \n
  • Rate Limiting — c'est une politique de sécurité. Vous dites : « Le client X peut faire au maximum 100 requêtes par minute ». Si la limite est dépassée — vous renvoyez 429 Too Many Requests. C'est la protection de votre backend.
  • \n
  • Throttling — c'est un mécanisme de contrôle de la vitesse. Vous décidez vous-même à quelle vitesse traiter les requêtes pour ne pas surcharger le CPU, les E/S ou la base de données. Le client peut envoyer 1000 requêtes, mais vous les traiterez à raison de 10 par seconde, les autres seront mises en file d'attente.
  • \n
\n\n

En Rust, les deux approches peuvent être implémentées avec les mêmes outils, mais avec une logique différente. Nous allons voir les deux.

\n\n

Algorithmes : Token Bucket et Leaky Bucket

\n\n

Les algorithmes les plus populaires pour le rate limiting sont Token Bucket et Leaky Bucket. Ils sont simples comme bonjour, mais incroyablement efficaces.

\n\n

Token Bucket (Seau de jetons)

\n

Imaginez un seau dans lequel N jetons tombent chaque seconde. Quand une requête arrive, elle prend un jeton. Si le seau est vide — la requête est rejetée. Rust est idéal pour implémenter cet algorithme grâce aux opérations atomiques.

\n\n

Leaky Bucket (Seau percé)

\n

Ici, le seau a un trou dans le fond par lequel s'écoule un nombre fixe de requêtes par seconde. Les requêtes tombent dans le seau par le haut. Si le seau déborde — les requêtes en trop sont rejetées. Cet algorithme est meilleur pour lisser les pics de charge.

\n\n

En Rust, nous n'écrirons pas ces algorithmes à la main (bien que ce soit instructif). Au lieu de cela, nous utiliserons le crate governor — la référence en matière de rate limiting dans l'écosystème Rust.

\n\n

Pratique : Installer Governor

\n\n

Le crate governor est une implémentation rapide, asynchrone et thread-safe de Token Bucket. Il supporte à la fois les modes synchrone et asynchrone, fonctionne avec tokio et async-std.

\n\n

Ajoutez dans Cargo.toml :

\n\n
[dependencies]\ngovernor = "0.6"\ntokio = { version = "1", features = ["full"] }\n
\n\n

Et maintenant, écrivons un simple rate limiter pour un serveur HTTP basé sur hyper ou axum. Pour simplifier, utilisons axum.

\n\n
use axum::{\n    extract::Request,\n    http::StatusCode,\n    middleware::{self, Next},\n    response::Response,\n    routing::get,\n    Router,\n};\nuse governor::{DefaultDirectRateLimiter, Quota, RateLimiter};\n                

Blogs

Book Recommendations