Rate Limiting in Rust: Efficient Load Management
Rate limiting is a key mechanism for protecting and optimizing web services, APIs, and network applications. In the Rust ecosystem, there are several mature libraries implementing various algorithms: from the classic token bucket to modern adaptive methods. In this article, we will cover three main libraries: governor, leaky-bucket, and ratelimit, with code examples and recommendations for selection.
1. The governor Library — The Gold Standard
governor is the most popular and flexible library for rate limiting. It implements the Generic Cell Rate Algorithm (GCRA), which ensures precise adherence to limits with minimal latency. It supports synchronous and asynchronous modes, as well as middleware for Actix-web, Axum, and Rocket.
Basic example with governor
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};use std::num::NonZeroU32;use std::time::Duration;
fn main() { // Allow 5 requests per second let quota = Quota::per_second(NonZeroU32::new(5).unwrap()); let limiter = RateLimiter::direct(quota);
for i in 0..10 { match limiter.check() { Ok(_) => println!("Request {} allowed", i), Err(_) => println!("Request {} denied (rate limit)", i), } std::thread::sleep(Duration::from_millis(100)); }}Asynchronous variant with waiting
use governor::{Quota, RateLimiter};use std::num::NonZeroU32;use tokio::time::{sleep, Duration};
#[tokio::main]async fn main() { let limiter = RateLimiter::direct(Quota::per_second( NonZeroU32::new(2).unwrap(), ));
for i in 0..5 { limiter.until_ready().await; println!("Processed request {}", i); sleep(Duration::from_millis(300)).await; }}Key features of governor:
- Support for keyed limits (per-IP, per-user) via
KeyedRateLimiter - Integration with
towermiddleware for HTTP servers - Configurable strategies: wait, deny, adaptive slowdown
- Minimal memory consumption (one atomic counter per limiter)
2. The leaky-bucket Library — Simplicity and Reliability
leaky-bucket implements the classic "leaky bucket" algorithm. It is ideal for smoothing out peak loads when a uniform flow of requests needs to be guaranteed. The library is lightweight and requires no external dependencies.
Example with leaky-bucket
use leaky_bucket::RateLimiter;use std::time::Duration;
#[tokio::main]async fn main() { let limiter = RateLimiter::builder() .initial(10) // initial token supply .interval(Duration::from_secs(1)) // refill interval .refill(5) // how many tokens to add per interval .max(20) // maximum number of tokens .build();
for i in 0..15 { limiter.acquire_one().await; println!("Request {} completed", i); }}Features of leaky-bucket:
- Support for asynchronous and blocking API
- Ability to configure "burst" mode (short-term spikes)
- Automatic token release during idle periods
3. The ratelimit Library — A Minimalist Approach
ratelimit is the simplest library, implementing a sliding window with fixed intervals. It is suitable for simple scenarios where high precision is not required.
Example with ratelimit
use ratelimit::Ratelimiter;use std::time::Duration;
fn main() { let mut limiter = Ratelimiter::builder(10, Duration::from_secs(1)) .