Nginx 如何实现限流?有哪些限流策略?
Nginx 提供了强大的限流功能,可以有效防止 DDoS 攻击、保护服务器资源、防止恶意请求。Nginx 的限流主要通过 limit_req 和 limit_conn 模块实现。
请求速率限制(limit_req):
nginxhttp { # 定义限流区域,基于客户端 IP limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; # 定义限流区域,基于请求 URI limit_req_zone $request_uri zone=uri:10m rate=5r/s; # 定义限流区域,基于服务器名称 limit_req_zone $server_name zone=server:10m rate=100r/s; server { listen 80; server_name example.com; # 应用限流 location / { limit_req zone=one burst=20 nodelay; proxy_pass http://backend; } # API 接口限流 location /api/ { limit_req zone=one burst=10 nodelay; limit_req_status 429; proxy_pass http://api_backend; } } }
参数说明:
-
limit_req_zone:定义限流区域
$binary_remote_addr:客户端 IP 地址(二进制格式,节省内存)zone=one:10m:区域名称和共享内存大小(10M 可存储约 16 万个 IP)rate=10r/s:每秒允许 10 个请求
-
limit_req:应用限流规则
zone=one:使用的限流区域burst=20:允许的突发请求数nodelay:不延迟处理突发请求
-
limit_req_status:超过限制时返回的状态码(默认 503)
连接数限制(limit_conn):
nginxhttp { # 定义连接数限制区域 limit_conn_zone $binary_remote_addr zone=addr:10m; # 定义服务器连接数限制区域 limit_conn_zone $server_name zone=server:10m; server { listen 80; server_name example.com; # 限制每个 IP 的并发连接数 limit_conn addr 10; # 限制服务器的总连接数 limit_conn server 1000; location / { proxy_pass http://backend; } } }
带宽限制:
nginxserver { listen 80; server_name example.com; location /download/ { # 限制下载速度为 1MB/s limit_rate 1m; # 前 10MB 不限速 limit_rate_after 10m; root /var/www/files; } }
综合限流配置:
nginxhttp { # 请求速率限制 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_req_zone $request_uri zone=uri_limit:10m rate=5r/s; # 连接数限制 limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # 状态码限制 limit_req_status 429; limit_conn_status 429; server { listen 80; server_name example.com; # 全局限流 limit_conn conn_limit 10; # 首页限流 location = / { limit_req zone=req_limit burst=20 nodelay; proxy_pass http://backend; } # API 接口严格限流 location /api/ { limit_req zone=req_limit burst=5 nodelay; limit_req zone=uri_limit burst=2 nodelay; proxy_pass http://api_backend; } # 下载限速 location /download/ { limit_rate 1m; limit_rate_after 10m; root /var/www/files; } # 静态资源不限流 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { root /var/www/static; } } }
白名单配置:
nginxhttp { # 定义限流区域 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; # 定义白名单 geo $limit_key { default $binary_remote_addr; 192.168.1.0/24 ""; 10.0.0.0/8 ""; } # 基于白名单的限流 limit_req_zone $limit_key zone=whitelist_limit:10m rate=10r/s; server { listen 80; server_name example.com; location / { limit_req zone=whitelist_limit burst=20 nodelay; proxy_pass http://backend; } } }
动态限流:
nginxhttp { # 根据请求方法限流 map $request_method $limit_key { default $binary_remote_addr; GET ""; HEAD ""; } limit_req_zone $limit_key zone=dynamic_limit:10m rate=10r/s; server { listen 80; server_name example.com; location / { limit_req zone=dynamic_limit burst=20 nodelay; proxy_pass http://backend; } } }
限流日志:
nginxhttp { # 自定义日志格式,包含限流信息 log_format limit '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'rt=$request_time limit=$limit_req_status'; access_log /var/log/nginx/access.log limit; # 限流区域 limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; server { listen 80; server_name example.com; location / { limit_req zone=req_limit burst=20 nodelay; limit_req_log_level warn; proxy_pass http://backend; } } }
限流策略选择:
- 固定窗口限流:
rate=10r/s,每秒固定请求数 - 滑动窗口限流:通过 burst 参数实现
- 令牌桶算法:Nginx 默认使用,允许突发流量
- 漏桶算法:通过
nodelay参数控制
实际应用场景:
1. API 接口限流:
nginxlimit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/min; location /api/ { limit_req zone=api_limit burst=10 nodelay; limit_req_status 429; add_header X-RateLimit-Limit "100"; add_header X-RateLimit-Remaining "90"; add_header X-RateLimit-Reset "60"; proxy_pass http://api_backend; }
2. 登录接口限流:
nginxlimit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/min; location /login { limit_req zone=login_limit burst=2 nodelay; limit_req_status 429; proxy_pass http://auth_backend; }
3. 文件下载限速:
nginxlocation /download/ { limit_rate 500k; limit_rate_after 5m; root /var/www/files; }
4. 防止暴力破解:
nginxlimit_req_zone $binary_remote_addr zone=auth_limit:10m rate=3r/min; location ~* ^/(login|register|reset-password) { limit_req zone=auth_limit burst=1 nodelay; limit_req_status 429; proxy_pass http://auth_backend; }
监控和调试:
nginx# 启用限流状态监控 location /limit_status { limit_req_status 429; add_header Content-Type text/plain; return 200 "Rate limit status: $limit_req_status"; } # 查看限流统计 location /nginx_status { stub_status on; access_log off; allow 127.0.0.1; deny all; }
最佳实践:
- 合理设置速率:根据业务需求设置合理的限流速率
- 使用 burst:允许一定程度的突发流量
- 返回友好错误:设置 429 状态码,返回友好提示
- 白名单机制:对可信 IP 放开限流
- 监控限流效果:定期检查限流日志,调整策略
- 分层限流:对不同接口设置不同的限流策略
- 结合缓存:对静态资源使用缓存,减少限流压力
性能考虑:
- 共享内存大小:根据 IP 数量合理设置 zone 大小
- 限流粒度:选择合适的限流键(IP、URI 等)
- 日志级别:生产环境使用 warn 级别,减少日志量
- nodelay 使用:根据场景选择是否使用 nodelay