Rate limiting in Rust: overview of libraries and tools
Rate limiting is a critical mechanism for protecting web services from overloads, DDoS attacks, and abuse. The Rust ecosystem offers several mature libraries for implementing rate limiting: from low-level algorithms to ready-made middleware for popular web frameworks. In this article, we'll explore three key approaches: governor (GCRA algorithm), leaky-bucket, and integration with Actix/Axum.
1. The governor library — GCRA algorithm
governor is the most popular rate limiting library in Rust, based on the Generic Cell Rate Algorithm (GCRA). This algorithm is used in network protocols and allows flexible configuration of both peak load and average rate.
Key features:
- Support for multiple keys (IP, User-Agent, API key)
- Configurable burst (traffic spike)
- Asynchronous operation via
tokioorasync-std - Lock-free thread safety
Example of setting a limit of 100 requests per minute with a burst of 20:
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};use std::num::NonZeroU32;use std::time::Duration;
#[tokio::main]async fn main() { // Limit: 100 requests per minute, burst 20 let quota = Quota::with_period(Duration::from_secs(60)) .unwrap() .allow_burst(NonZeroU32::new(20).unwrap()); let limiter = DefaultKeyedRateLimiter::::new(quota); // Check for user "user123" match limiter.check_key("user123") { Ok(_) => println!("Request allowed"), Err(_) => println!("Limit exceeded, status 429"), }} 2. The leaky-bucket library
The leaky bucket algorithm is implemented in the leaky-bucket library. It models a bucket of water that fills with requests and leaks at a constant rate. Suitable for smoothing out traffic spikes.
Features:
- Simple model: a bucket with capacity for N requests
- Leak rate — number of requests per second
- Support for maximum pending requests
Example with a limit of 5 requests per second and a bucket of 10:
use leaky_bucket::RateLimiter;use std::time::Duration;
#[tokio::main]async fn main() { let limiter = RateLimiter::builder() .initial(10) // initial number of tokens .max(10) // maximum bucket size .interval(Duration::from_millis(200)) // refill every 200 ms .build(); // Attempt to acquire a token if limiter.try_acquire().is_ok() { println!("Request processed"); } else { println!("Bucket empty, denied"); }}3. Middleware for web frameworks
Ready-made middleware significantly simplifies integrating rate limiting into web servers built with Actix and Axum.
Actix + governor
use actix_web::{web, App, HttpServer, HttpRequest, HttpResponse, middleware::from_fn};use governor::{DefaultKeyedRateLimiter, Quota};use std::num::NonZeroU32;use std::time::Duration;
async fn rate_limit_middleware( req: HttpRequest, limiter: web::Data<DefaultKeyedRateLimiter<String>>,) -> Result<HttpResponse, actix_web::Error> { let client_ip = req.peer_addr() .map(|addr| addr.to_string()) .unwrap_or_default(); match limiter.check_key(&client_ip) { Ok(_) => Ok(HttpResponse::Ok().body("OK")), Err(_) => Ok(HttpResponse::TooManyRequests().body("Too Many Requests")), }} Also in library
C++ Application Monitoring: Tools and Libraries
Internationalization (i18n) in PHP: gettext library and modern approaches
HTTP client for Java: overview of top libraries (Java 11, Apache, OkHttp, Retrofit)