C++中的速率限制:用于API保护的库与实现

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

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

开始课程

C++中的速率限制:工具概览与实现



速率限制(Rate limiting)是保护Web服务、API和微服务免受过载、DDoS攻击和资源滥用的一种关键机制。在C++生态系统中,有几种成熟的库和方法可用于实现速率限制。在本文中,我们将介绍主要算法、流行的库,并编写代码示例。



流行的速率限制算法



在选择库之前,了解其底层算法会很有帮助:



  • Token Bucket(令牌桶) — 令牌以固定速率添加,每个请求消耗一个令牌。如果没有令牌,请求将被拒绝。简单且高效。
  • Sliding Window(滑动窗口) — 统计最近一个时间间隔内的请求数量(例如,1秒内10个请求)。
  • Fixed Window(固定窗口) — 在固定时间段内对请求进行简单计数(例如,每分钟计数器重置)。
  • Leaky Bucket(漏桶) — 请求被放入队列并以恒定速率处理,超出部分被丢弃。


C++中用于速率限制的库



1. Boost.Token Bucket(Boost.Timer + 手动实现)



Boost中没有现成的令牌桶实现,但可以很容易地基于boost::timer或std::chrono编写。然而,对于生产级解决方案,最好使用功能完备的库。



2. libcppa(C++ Actor Framework)



libcppa库(现在是CAF — C++ Actor Framework的一部分)为actor提供了内置的速率限制机制。它允许限制单位时间内的消息数量。



#include <caf/all.hpp>

using namespace caf;

behavior rate_limited_actor(event_based_actor* self, int max_requests, duration period) { auto limiter = self->make_rate_limiter(max_requests, period); return { [=](const std::string& msg) { if (limiter->try_acquire()) { aout(self) << "Processed: " << msg << endl; } else { aout(self) << "Rate limit exceeded for: " << msg << endl; } } };}


3. userver(来自Yandex)



来自Yandex的userver框架是一个用于C++高负载服务的强大解决方案。它通过components::RateLimiter和utils::TokenBucket内置了对速率限制的支持。



#include <userver/utils/token_bucket.hpp>

using namespace userver;

int main() { utils::TokenBucket limiter(10, std::chrono::seconds(1)); // 每秒10个请求 for (int i = 0; i < 20; ++i) { if (limiter.TryObtain()) { std::cout << "Request " << i << " allowed"; } else { std::cout << "Request " << i << " blocked"; } std::this_thread::sleep_for(std::chrono::milliseconds(50)); } return 0;}


4. Pistache(带速率限制的HTTP框架)



用于创建HTTP服务器的Pistache库具有内置的速率限制中间件。示例:



#include <pistache/endpoint.h>#include <pistache/router.h>#include <pistache/http.h>

using namespace Pistache;

int main() { Http::Endpoint server(Address(Ipv4::any(), Port(9080))); auto router = std::make_shared<Rest::Router>(); // 内置速率限制器:每秒5个请求 router->addMiddleware(Http::Middleware::RateLimit(5, std::chrono::seconds(1))); Rest::Routes::Get(*router, "/api/resource", [](const Rest::Request& req, Http::ResponseWri

推荐