在 Nginx 负载均衡架构中,通过 http 块定义 limit_req_zone 并在 location 块启用 limit_req,是防止单一 IP 高频请求耗尽后端资源的有效方法。但必须预留 burst 空间以适应正常业务波动,同时配置白名单避免误伤运维监控流量。
先说结论:限流是止损手段而非根治方案,适合在攻击流量特征明显且业务允许一定延迟的场景下优先部署。
- 先判断:确认攻击是否针对特定接口或 URI,避免全局误杀。
- 优先做:基于 $binary_remote_addr 定义限流区,设置合理的 rate 和 burst,并配置运维白名单。
- 再验证:观察 access.log 中 503 状态码比例,确认是否影响正常用户。
生产环境配置示例
以下是包含负载均衡、白名单及限流保护的完整配置片段。请根据实际业务 QPS 调整 rate 值,并将白名单 IP 替换为实际运维网段。
http {
# 1. 定义 IP 白名单 (geo 模块)
geo $limit_white {
default 0;
10.0.0.0/8 1; # 内网网段
192.168.1.100 1; # 运维堡垒机 IP
}
# 2. 定义限流区,key 为客户端 IP,内存 10m,速率需按业务调整
# log_level 设为 warn 避免正常限流日志泛滥
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req_log_level warn;
limit_req_status 503;
# 3. 定义后端上游服务器组
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
server {
listen 80;
server_name example.com;
location / {
# 4. 白名单跳过限流
if ($limit_white) {
set $limit_white 0;
}
# 注意:if 在 location 中性能较差,生产环境建议在 http 层通过 map 或单独 server 块处理白名单
# 更推荐写法:在 limit_req_zone 前通过 map 变量控制 key,或使用 allow/deny 指令
# 5. 应用限流,允许突发 20 个请求,nodelay 表示超出 burst 立即拒绝
limit_req zone=one burst=20 nodelay;
# 6. 代理到后端负载均衡
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 7. 自定义 503 错误页面,避免返回默认 Nginx 页面暴露版本
error_page 503 /503.html;
location = /503.html {
internal;
root /usr/share/nginx/html;
}
}
}限流原理简述
CC 攻击的本质是模拟正常用户发送大量请求,耗尽服务器连接数或 CPU 资源。Nginx 的 limit_req 模块使用漏桶算法(leaky bucket algorithm),以固定速率处理请求,多余的请求会被延迟或直接拒绝。在负载均衡前端做这一步,可以避免无效请求穿透到后端应用服务器,保护数据库和业务逻辑层。
参数调优建议
配置中的 rate 和 burst 值不能盲目复制,需结合业务监控数据:
- rate 计算:统计正常业务高峰期的单 IP 平均 QPS。例如正常用户每秒请求 5 次,可设置 rate=5r/s 或略高。示例中的 10r/s 仅适用于低频接口。
- burst 设置:用于应对瞬间流量波动。若业务允许短暂排队,可设置 burst=20;若需严格保护后端,配合 nodelay 参数直接拒绝超出部分。
- key 选择:默认使用 $binary_remote_addr。若业务存在大量 NAT 共享 IP(如移动端),可考虑结合 $http_x_forwarded_for 或 Cookie 进行更细粒度限流。
效果验证方法
配置生效后,需通过压测和日志分析验证策略是否生效且未误伤:
1. 模拟高频请求:在测试环境使用 ab 工具发起高频请求,观察是否触发 503。
ab -n 1000 -c 100 http://your-domain.com/2. 查看限流日志:检查 Nginx error.log,搜索 "limiting requests" 关键字,确认限流触发记录。
grep "limiting requests" /var/log/nginx/error.log3. 监控后端负载:对比开启限流前后,后端服务器的 CPU 负载和连接数是否有明显下降。
4. 白名单验证:使用白名单内的 IP 发起高频请求,确认不应被限流(状态码应为 200 而非 503)。
常见风险与排查
1. 运维 IP 被误封:未配置白名单可能导致运维管理 IP、健康检查探针或监控系统的请求被限制,导致故障排查困难。务必在 limit_req 前通过 geo 或 allow 指令放行可信 IP。
2. 日志泛滥:默认情况下,限流触发会记录日志。若攻击流量大,error.log 可能迅速写满。建议设置 limit_req_log_level warn 或 error,减少 info 级别日志。
3. 静态资源限流:不要对 css、js、图片等静态资源启用严格的 limit_req,否则页面加载会失败。建议仅对 API 接口或动态请求 location 启用限流。
4. Nginx 自身性能:limit_req 是在 Nginx 层处理,如果攻击流量极大,Nginx 本身可能成为瓶颈,需结合 upstream 健康检查和多节点部署,必要时接入 WAF 或 CDN 清洗流量。
参考来源
- Nginx 官方文档 - ngx_http_limit_req_module: https://nginx.org/en/docs/http/ngx_http_limit_req_module.html