Rate Limiting en Rust : bibliothèques pour limiter la fréquence des requêtes

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

Rate Limiting en Rust : gestion efficace de la charge

\n\n

Le rate limiting (limitation de la fréquence des requêtes) est un mécanisme clé pour la protection et l'optimisation des services web, API et applications réseau. Dans l'écosystème Rust, il existe plusieurs bibliothèques matures implémentant différents algorithmes : du classique token-bucket aux méthodes adaptatives modernes. Dans cet article, nous analyserons trois bibliothèques principales : governor, leaky-bucket et ratelimit, avec des exemples de code et des recommandations pour choisir.

\n\n

1. Bibliothèque governor — l'étalon-or

\n\n

governor est la bibliothèque la plus populaire et la plus flexible pour le rate limiting. Elle implémente l'algorithme Generic Cell Rate Algorithm (GCRA), qui garantit le respect précis des limites avec un délai minimal. Elle prend en charge les modes synchrone et asynchrone, ainsi que les middlewares pour Actix-web, Axum et Rocket.

\n\n

Exemple de base avec governor

\n
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};\nuse std::num::NonZeroU32;\nuse std::time::Duration;\n\nfn main() {\n    // Autoriser 5 requêtes par seconde\n    let quota = Quota::per_second(NonZeroU32::new(5).unwrap());\n    let limiter = RateLimiter::direct(quota);\n\n    for i in 0..10 {\n        match limiter.check() {\n            Ok(_) => println!("Requête {} autorisée", i),\n            Err(_) => println!("Requête {} rejetée (rate limit)", i),\n        }\n        std::thread::sleep(Duration::from_millis(100));\n    }\n}
\n\n

Variante asynchrone avec attente

\n
use governor::{Quota, RateLimiter};\nuse std::num::NonZeroU32;\nuse tokio::time::{sleep, Duration};\n\n#[tokio::main]\nasync fn main() {\n    let limiter = RateLimiter::direct(Quota::per_second(\n        NonZeroU32::new(2).unwrap(),\n    ));\n\n    for i in 0..5 {\n        limiter.until_ready().await;\n        println!("Requête {} traitée", i);\n        sleep(Duration::from_millis(300)).await;\n    }\n}
\n\n

Fonctionnalités clés de governor :

\n
    \n
  • Prise en charge des limites par clé (par IP, par utilisateur) via KeyedRateLimiter
  • \n
  • Intégration avec le middleware tower pour les serveurs HTTP
  • \n
  • Stratégies configurables : attente, rejet, ralentissement adaptatif
  • \n
  • Consommation mémoire minimale (un compteur atomique par limiteur)
  • \n
\n\n

2. Bibliothèque leaky-bucket — simplicité et fiabilité

\n\n

leaky-bucket implémente l'algorithme classique du « seau percé ». Il est idéal pour lisser les pics de charge lorsqu'il faut garantir un flux de requêtes uniforme. La bibliothèque est légère et ne nécessite pas de dépendances externes.

\n\n

Exemple avec leaky-bucket

\n
use leaky_bucket::RateLimiter;\nuse std::time::Duration;\n\n#[tokio::main]\nasync fn main() {\n    let limiter = RateLimiter::builder()\n        .initial(10)        // réserve initiale de jetons\n        .interval(Duration::from_secs(1))  // intervalle de recharge\n        .refill(5)          // nombre de jetons ajoutés par intervalle\n        .max(20)            // nombre maximum de jetons\n        .build();\n\n    for i in 0..15 {\n        limiter.acquire_one().await;\n        println!("Requête {} exécutée", i);\n    }\n}
\n\n

Caractéristiques de leaky-bucket :

\n
    \n
  • Prise en charge de l'API asynchrone et bloquante
  • \n
  • Possibilité de configurer le mode « burst » (pics temporaires)
  • \n
  • Libération automatique des jetons en période d'inactivité
  • \n
\n\n

3. Bibliothèque ratelimit — approche minimaliste

\n\n

ratelimit est la bibliothèque la plus simple, implémentant une fenêtre glissante avec des intervalles fixes. Elle convient aux scénarios simples où une grande précision n'est pas nécessaire.

\n\n

Exemple avec ratelimit

\n
use ratelimit::Ratelimiter;\nuse std::time::Duration;\n\nfn main() {\n    let mut limiter = Ratelimiter::builder(10, Duration::from_secs(1))\n        .                    

Recommendations