#rate-limiting #axum #gcra #middleware

axum_gcra

基于 GCRA 的 Axum 速率限制器,具有按路由/按键速率限制功能

6 个版本

0.1.1 2024 年 8 月 11 日
0.1.0 2024 年 8 月 11 日
0.1.0-beta.12024 年 8 月 10 日
0.1.0-alpha.12024 年 8 月 8 日

#387Web 编程

Download history 336/week @ 2024-08-05 61/week @ 2024-08-12

每月 397 次下载

MIT/Apache

49KB
866

axum_gcra

基于 GCRA 的 Axum 速率限制器,具有按路由/按键速率限制功能。

crates.io Documentation MIT/Apache-2 licensed

摘要

此 crate 提供了一个使用 GCRA 算法实现的强大速率限制 LayerService,为 axum 提供平均吞吐量和突发请求限制。而不是为所有路由提供一个全局速率限制器,此 crate 允许为单个路由/路径配置单独的速率限制配额,并从请求中提取任意键以进行额外的隔离。

例如

use std::time::Duration;

use axum::{routing::get, Router, http::Method};
use axum_gcra::{gcra::Quota, RateLimitLayer, real_ip::RealIp};

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(|| async { "Hello, World!" }))
        .route("/hello", get(|| async { "Hello, Again!" }))
        .route_layer(
            RateLimitLayer::<RealIp>::builder()
                .with_default_quota(Quota::simple(Duration::from_secs(5)))
                .with_route((Method::GET, "/"), Quota::simple(Duration::from_secs(1)))
                .with_route((Method::GET, "/hello"), Quota::simple(Duration::from_secs(2)))
                .with_global_fallback(true)
                .with_extension(true)
                .default_handle_error(),
        );

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

为了使速率限制器能够区分不同的客户端,可以使用从请求中提取的单个或组合键配置 RateLimitLayer。例如,为了根据客户端的 IP 地址进行速率限制,可以使用提供的 RealIp 提取器

use axum::{routing::get, Router, extract::Extension};
use axum_gcra::{RateLimitLayer, real_ip::RealIp, extensions::RateLimiter};

type Key = RealIp; // could also be `(RealIp, UserSession)`, for example.

let app = Router::<()>::new()
    // keys are any type that can implement `FromRequestParts` and `axum_gcra::Key`
    .route("/", get(|ip: RealIp| async move { format!("Hello, {ip}!") }))
    // The key type must also be specified when extracting the `RateLimiter` extension.
    .route("/extension", get(|rl: Extension<RateLimiter<Key>>| async move {
        // do something with the rate limiter, etc.
        "Hello, Extensions!"
    }))
    .route_layer(RateLimitLayer::<Key>::builder().default_handle_error());

有关更多信息,请参阅 RealIp 的文档。

垃圾回收

内部,速率限制器使用共享哈希表结构来存储每个键的状态。为了避免无限增长,提供了一个垃圾回收机制,将删除已过期且不再需要的条目。这可以根据处理请求的数量或基于固定时间间隔的后台任务进行配置。例如

use std::time::Duration;
use axum::{routing::get, Router};
use axum_gcra::{RateLimitLayer, real_ip::RealIp};

let app = Router::<()>::new()
    .route("/", get(|| async { "Hello, World!" }))
    .route_layer(
        RateLimitLayer::<RealIp>::builder()
            .with_gc_interval(1000) // run GC on every 1000th request
            .with_gc_interval(Duration::from_secs(60)) // or run every 60 seconds
            .default_handle_error(),
    );

有关更多信息,请参阅 GCInterval 的文档。

依赖项

~6–16MB
~190K SLoC