Rust中的速率限制与节流:掌控数据流

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

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

开始课程

当Rust遭遇过载:为什么你的服务会“崩溃”?

\n\n

想象一下,你用Rust编写了一个完美的高负载服务。它运行飞快,充分利用了零成本抽象和内存所有权的优势。但问题来了——一个“贪婪”的客户端出现,开始以每秒数千个请求的频率冲击你的服务器。会发生什么?数据库崩溃?队列堵塞?或者更糟的是,你被自己调用的外部API封禁了?

\n\n

在Rust中,与其他任何语言一样,没有速率限制和节流是行不通的。这不仅仅是“良好实践”——而是你的应用程序在生产环境中生存的关键。但Rust有一个特点:我们喜欢高效地从头开始构建一切。不过,你不需要重新发明轮子——我们有强大的crate(库)和优雅的模式。

\n\n

在本文中,我们将探讨如何正确地在Rust中实现请求限制,使用经典算法(令牌桶)和现代异步方法。你将了解如何保护你的API免受DDoS攻击,如何不超出外部服务的限制,以及如何编写你自己的节流器,使其比Go或Python运行得更快。

\n\n

速率限制 vs 节流:有什么区别?

\n\n

在深入代码之前,让我们一劳永逸地弄清楚这些术语。它们经常被混淆,但区别至关重要。

\n\n
    \n
  • 速率限制——这是一种安全策略。你规定:“客户端X每分钟最多只能发出100个请求”。如果超过限制——返回429 Too Many Requests。这是为了保护你的后端。
  • \n
  • 节流——这是一种速度控制机制。你自己决定以多快的速度处理请求,以免过载CPU、I/O或数据库。客户端可以发送1000个请求,但你每秒只处理10个,其余的放入队列。
  • \n
\n\n

在Rust中,两种方法都可以使用相同的工具集实现,但逻辑不同。我们将讨论这两种方法。

\n\n

算法:令牌桶和漏桶

\n\n

最流行的速率限制算法是令牌桶和漏桶。它们简单如靴子,但非常高效。

\n\n

令牌桶

\n

想象一个桶,每秒滴入N个令牌。当请求到来时,它取走一个令牌。如果桶空了——请求被拒绝。由于原子操作,Rust非常适合实现这种算法。

\n\n

漏桶

\n

这里,桶底有一个洞,每秒漏出固定数量的请求。请求从顶部进入桶中。如果桶满了——多余的请求被丢弃。这种算法更适合平滑峰值负载。

\n\n

在Rust中,我们不会手动编写这些算法(尽管这很有教育意义)。相反,我们将使用governor crate——Rust生态系统中速率限制的黄金标准。

\n\n

实践:安装Governor

\n\n

governor crate是一个快速、异步且线程安全的令牌桶实现。它支持同步和异步模式,可与tokio和async-std一起使用。

\n\n

在Cargo.toml中添加:

\n\n
[dependencies]\ngovernor = "0.6"\ntokio = { version = "1", features = ["full"] }\n
\n\n

现在,让我们为基于hyper或axum的HTTP服务器编写一个简单的速率限制器。为简单起见,我们使用axum。

\n\n
use axum::{\n    extract::Request,\n    http::StatusCode,\n    middleware::{self, Next},\n    response::Response,\n    routing::get,\n    Router,\n};\nuse governor::{DefaultDirectRateLimiter, Quota, RateLimiter};\n                

博客

书籍推荐