Rust中的速率限制:governor、leaky-bucket库及Web服务器中间件

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Rust中的速率限制:库与工具概览



速率限制(请求频率限制)是保护Web服务免受过载、DDoS攻击和滥用的关键机制。在Rust生态系统中,有多个成熟的库可用于实现速率限制:从底层算法到流行Web框架的现成中间件。本文将探讨三种核心方法:governor(GCRA算法)、leaky-bucket(漏桶算法)以及与Actix/Axum的集成。



1. governor库——GCRA算法



governor是Rust中最流行的速率限制库,基于通用信元速率算法(GCRA)。该算法用于网络协议,可灵活配置峰值负载和平均速率。



主要特性:

  • 支持多种键(IP、User-Agent、API密钥)
  • 可配置的突发流量(burst)
  • 通过tokio或async-std实现异步操作
  • 无锁线程安全


设置每分钟100个请求、突发20个的示例:



use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};use std::num::NonZeroU32;use std::time::Duration;

#[tokio::main]async fn main() { // 限制:每分钟100个请求,突发20个 let quota = Quota::with_period(Duration::from_secs(60)) .unwrap() .allow_burst(NonZeroU32::new(20).unwrap()); let limiter = DefaultKeyedRateLimiter::::new(quota); // 检查用户"user123" match limiter.check_key("user123") { Ok(_) => println!("请求已允许"), Err(_) => println!("超出限制,状态码429"), }}


2. leaky-bucket库——漏桶算法



漏桶算法在leaky-bucket库中实现。它模拟一个水桶,请求注入其中并以恒定速率漏出。适用于平滑峰值负载。



特点:

  • 简单模型:容量为N个请求的桶
  • 泄漏速率:每秒请求数
  • 支持最大等待请求数


每秒5个请求、桶容量为10的示例:



use leaky_bucket::RateLimiter;use std::time::Duration;

#[tokio::main]async fn main() { let limiter = RateLimiter::builder() .initial(10) // 初始令牌数 .max(10) // 桶的最大容量 .interval(Duration::from_millis(200)) // 每200毫秒补充一次 .build(); // 尝试获取令牌 if limiter.try_acquire().is_ok() { println!("请求已处理"); } else { println!("桶已空,拒绝请求"); }}


3. Web框架中间件



现成的中间件大大简化了在Actix和Axum Web服务器中集成速率限制的过程。



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

推荐