限流 API 文档
概述
UVHTTP 提供服务器级别的限流功能,用于防止 DDoS 攻击和过载。限流功能可以在编译时通过宏配置启用或禁用。
特性
- 服务器级别限流:所有请求共享同一个限流计数器
- 固定窗口算法:简单高效的限流算法
- IP 白名单:支持 IP 地址白名单,不受限流限制
- 零开销:通过条件编译实现,禁用时无运行时开销
- 可配置:支持自定义最大请求数和时间窗口
编译配置
启用限流功能(默认)
bash
make build禁用限流功能
编辑 CMakeLists.txt,将 option(UVHTTP_FEATURE_RATE_LIMIT ...) 的默认值改为 OFF,然后运行:
bash
make buildAPI 参考
启用限流
c
uvhttp_error_t uvhttp_server_enable_rate_limit(
uvhttp_server_t* server,
int max_requests,
int window_seconds
);参数:
server: 服务器实例max_requests: 时间窗口内允许的最大请求数(范围:1-1000000)window_seconds: 时间窗口(秒)(范围:1-86400)
返回值:
UVHTTP_OK: 成功UVHTTP_ERROR_INVALID_PARAM: 参数无效
说明:
- 使用固定窗口算法实现限流
- 限流状态直接嵌入到服务器结构体中,无需动态内存分配
- 所有请求共享同一个限流计数器(服务器级别限流)
示例:
c
// 每秒最多 1000 个请求
uvhttp_server_enable_rate_limit(server, 1000, 1);
// 每分钟最多 6000 个请求
uvhttp_server_enable_rate_limit(server, 6000, 60);禁用限流
c
uvhttp_error_t uvhttp_server_disable_rate_limit(uvhttp_server_t* server);参数:
server: 服务器实例
返回值:
UVHTTP_OK: 成功UVHTTP_ERROR_INVALID_PARAM: 参数无效
示例:
c
uvhttp_server_disable_rate_limit(server);添加 IP 白名单
c
uvhttp_error_t uvhttp_server_add_rate_limit_whitelist(
uvhttp_server_t* server,
const char* client_ip
);参数:
server: 服务器实例client_ip: 客户端 IP 地址(如 "127.0.0.1")
返回值:
UVHTTP_OK: 成功UVHTTP_ERROR_INVALID_PARAM: 参数无效UVHTTP_ERROR_OUT_OF_MEMORY: 内存分配失败
示例:
c
// 本地回环地址不受限流
uvhttp_server_add_rate_limit_whitelist(server, "127.0.0.1");
// 内网地址不受限流
uvhttp_server_add_rate_limit_whitelist(server, "10.0.0.1");获取限流状态
c
uvhttp_error_t uvhttp_server_get_rate_limit_status(
uvhttp_server_t* server,
const char* client_ip,
int* remaining,
uint64_t* reset_time
);参数:
server: 服务器实例client_ip: 客户端 IP 地址(当前未使用,保留以备将来扩展)remaining: 剩余请求数(输出参数)reset_time: 重置时间戳(毫秒)(输出参数)
返回值:
UVHTTP_OK: 成功UVHTTP_ERROR_INVALID_PARAM: 参数无效
注意:
- 当前实现是服务器级别限流,
client_ip参数未使用 - 返回的
remaining和reset_time是服务器级别的状态
示例:
c
int remaining;
uint64_t reset_time;
uvhttp_server_get_rate_limit_status(server, "127.0.0.1", &remaining, &reset_time);
printf("剩余请求数: %d, 重置时间: %lu\n", remaining, reset_time);重置客户端限流状态
c
uvhttp_error_t uvhttp_server_reset_rate_limit_client(
uvhttp_server_t* server,
const char* client_ip
);参数:
server: 服务器实例client_ip: 客户端 IP 地址(当前未使用,保留以备将来扩展)
返回值:
UVHTTP_OK: 成功UVHTTP_ERROR_INVALID_PARAM: 参数无效
注意:
- 当前实现会重置整个服务器的限流计数器
client_ip参数未使用,保留以备将来扩展
示例:
c
uvhttp_server_reset_rate_limit_client(server, "127.0.0.1");清空所有限流状态
c
uvhttp_error_t uvhttp_server_clear_rate_limit_all(uvhttp_server_t* server);参数:
server: 服务器实例
返回值:
UVHTTP_OK: 成功UVHTTP_ERROR_INVALID_PARAM: 参数无效
示例:
c
uvhttp_server_clear_rate_limit_all(server);使用示例
基本使用
c
#include "uvhttp.h"
int main() {
uv_loop_t* loop = uv_default_loop();
uvhttp_server_t* server = NULL;
uvhttp_server_new(loop, &server);
// 启用限流:每秒最多 1000 个请求
uvhttp_server_enable_rate_limit(server, 1000, 1);
// 添加白名单
uvhttp_server_add_rate_limit_whitelist(server, "127.0.0.1");
// 启动服务器
uvhttp_server_listen(server, "0.0.0.0", 8080);
uv_run(loop, UV_RUN_DEFAULT);
uvhttp_server_free(server);
return 0;
}动态调整限流
c
// 在运行时调整限流参数
void adjust_rate_limit(uvhttp_server_t* server, int new_max_requests) {
// 先禁用
uvhttp_server_disable_rate_limit(server);
// 重新启用
uvhttp_server_enable_rate_limit(server, new_max_requests, 1);
}限流响应
当请求超过限流时,服务器会返回:
- 状态码: 429 Too Many Requests
- Content-Type: text/plain
- Retry-After: 60(建议 60 秒后重试)
- 响应体: "Too Many Requests"
设计说明
服务器级别限流
当前实现使用服务器级别的限流,所有请求共享同一个限流计数器。这种设计适合:
- DDoS 防护:限制服务器接收的总请求量
- 资源保护:防止服务器因过载而崩溃
- 简单高效:无需维护每个客户端的状态
为什么不是客户端级别?
客户端级别的限流需要:
- 为每个客户端维护独立的限流状态
- 使用哈希表存储客户端状态
- 定期清理过期的客户端状态
- 更复杂的内存管理
对于 DDoS 防护场景,服务器级别限流已经足够,而且:
- 性能更好:无需哈希表查找
- 内存更少:只有一个计数器
- 实现简单:代码更易维护
未来扩展
如果需要客户端级别的限流,可以考虑:
- 使用
uthash库存储客户端状态 - 实现滑动窗口算法
- 添加客户端状态过期机制
- 提供更细粒度的限流控制
错误码
限流相关的错误码:
c
UVHTTP_ERROR_RATE_LIMIT_EXCEEDED = -550 // 超过限流性能考虑
- 时间复杂度: O(1) - 固定窗口算法
- 空间复杂度: O(1) - 只维护一个计数器
- 吞吐量: ~819,000 检查/秒
- 平均延迟: ~1.2 微秒
- 内存占用: 12 字节(限流上下文)
- 开销: 极小,只有简单的计数和比较操作
性能优化
- 零内存分配:限流状态直接嵌入到服务器结构体中,无需动态内存分配
- 缓存友好:所有热点数据在同一缓存行,减少缓存未命中
- 无指针解引用:直接访问结构体字段,比通过指针访问更快
- 编译期优化:通过条件编译实现,禁用时无运行时开销
最佳实践
合理配置限流参数
- 根据服务器性能设置
max_requests - 根据业务需求设置
window_seconds - 避免过于严格的限流影响正常用户
- 根据服务器性能设置
使用白名单
- 将受信任的 IP 地址添加到白名单
- 包括监控系统、内部服务等
- 避免限流影响关键服务
监控限流状态
- 定期检查
remaining和reset_time - 记录限流触发事件
- 根据实际情况调整参数
- 定期检查
优雅降级
- 超过限流时返回清晰的错误信息
- 提供
Retry-After头 - 考虑实现缓存层减轻服务器压力