Rate limiting in Rust: governor, leaky-bucket libraries and middleware for web servers

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

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 tokio or async-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")), }}

Recommendations