nginx利用内置模块配置限速限流
有时候 NGINX 面对一些特殊的场景时,需要进行一定的限速限流的配置,比如一个官网,可能前端静态文件是非常小的,但是同时配置的还有一些 apk 包,这些包如果不做任何限制,可能会形成比较大的负载或者带宽的压力。
# 1. 限速限流的典型应用场景
场景一:下载站带宽控制
文件下载类网站需要控制单个下载线程的速度,避免少数大文件下载占用全部带宽,影响其他用户的访问体验。
场景二:API 接口防刷
对外提供的 API 接口需要限制请求频率,防止恶意刷接口或意外的大量并发请求导致服务不可用。
场景三:防止爬虫过度抓取
限制爬虫的访问频率,既保护服务器资源,又避免对后端服务造成过大压力。
# 2. 限速限流的原理
Nginx 的限速限流主要通过两个模块实现:
ngx_http_limit_conn_module:限制连接数ngx_http_limit_req_module:限制请求频率
两者的工作机制不同:
- 连接数限制:基于并发连接数,限制同一 IP 同时建立的连接数量
- 请求频率限制:基于请求速率,限制每秒/分钟处理的请求数量
# 3. 配置详解
版本说明
本文写于 2019-08,基于 Nginx 1.15。
未在更高版本上重新验证,请以对应版本的官方文档为准。
没有限制之前,对应的包下载速度如下:

添加如下配置,进行一定的限制:
http {
...#省略
limit_conn_zone $binary_remote_addr zone=addr:10m;
...#省略
}
server {
listen 80 default;
server_name localhost;
location ~ "^/test/app/" {
limit_conn addr 6;
limit_rate_after 10m;
limit_rate 1200k;
limit_conn_status 499;
limit_conn_log_level warn;
root /app;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
说明:
- http 区域使用的是 1.15 版本,默认已安装
ngx_http_limit_conn_module。limit_conn_zone:固定名称,下边调用时对应。$binary_remote_addr:通过 remote_addr 标识做限制,"binary_" 前缀缩写内存占用量,限制同一客户端 IP 地址。zone=addr:10m:生成大小为 10M、名字为 addr 的内存区域,用来存储访问频次信息。
- server 区域可写在 server 内表示限制所有,也可写到 location 中表示单独区域限制。
limit_conn:单个 IP 限制最大连接数为 6。limit_rate_after:请求前 10M 大小时不限速。limit_rate:单个连接最大带宽限制为 1200K。limit_conn_status:设置拒绝请求的返回值(400-599 之间,默认 503)。limit_conn_log_level:定义日志级别,默认 error。
# 4. 验证效果
现在测试一下下载速度:

可以看到速度已经受限,而且是在 10M 之后速度开始慢慢下降,直至达到限制位置。
压测验证:
ab -n 10 -c 10 http://www.test.com/res/app/app-xiaomi-release.apk
此命令表示请求 10 次资源,并发为 10。查看日志,因为定义的最大并发是 6,所以会有 4 个失败(返回 499),6 个成功:
$tailf -n 100 a |awk -F "," '{print $6}'
"response": "499"
"response": "499"
"response": "499"
"response": "499"
"response": "200"
"response": "200"
"response": "200"
"response": "200"
"response": "200"
"response": "200"
2
3
4
5
6
7
8
9
10
11
压测输出中,Transfer rate 约为 7M/s,正好是单条限制 1.2M/s 乘以 6 的数值。
# 5. 坑与边界
常见问题一:限速不生效
检查是否在正确的层级配置,limit_conn_zone 必须在 http 层,limit_conn 必须在 server 或 location 层。
常见问题二:内存占用过高
如果连接数很大,需要适当增大 zone 大小。使用 $binary_remote_addr 而非 $remote_addr 可以显著减少内存占用。
常见问题三:与其他模块冲突
与 proxy_cache 等模块配合使用时,注意缓存命中后的行为可能影响限速效果。
# 6. 进阶:请求频率限制
除了连接数限制,还可以用 limit_req 限制请求频率:
http {
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
}
server {
location /api/ {
limit_req zone=req_limit burst=20 nodelay;
}
}
2
3
4
5
6
7
8
9
rate=10r/s:每秒 10 个请求burst=20:允许突发 20 个请求nodelay:不等待,立即处理突发请求
# 7. 参考
# 8. 更多高级配置示例
示例一:基于用户身份的限速
如果需要根据登录用户而不是 IP 来限速,可以使用会话 cookie 或 JWT token:
http {
limit_req_zone $cookie_session_id zone=session_limit:10m rate=5r/s;
}
server {
location /api/ {
limit_req zone=session_limit burst=10 nodelay;
}
}
2
3
4
5
6
7
8
9
示例二:不同路径不同限速策略
server {
# 下载路径:限制带宽
location /download/ {
limit_rate 1024k; # 单连接 1MB/s
}
# API 路径:限制请求频率
location /api/ {
limit_req zone=api_limit:10m rate=100r/s;
}
# 上传路径:限制连接数
location /upload/ {
limit_conn upload_limit 3;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
示例三:区域白名单
有时需要对某些 IP 段不做限速(比如内部服务):
geo $limited {
default 1;
<内部IP段> 0;
<内部IP段> 0;
<内部IP段> 0;
}
map $limited $limit {
1 $binary_remote_addr;
0 "";
}
http {
limit_conn_zone $limit zone=addr:10m;
}
### 9. 参考
- [Nginx 限速模块官方文档](http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html)
- [Nginx 请求频率限制文档](http://nginx.org/en/docs/http/ngx_http_limit_req_module.html)
## 12. 限速与缓存的交互
当 Nginx 同时使用限速和缓存时,需要注意缓存命中后的行为:
**场景**:启用了 proxy_cache,同时配置了 limit_req
```nginx
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
proxy_cache my_cache;
proxy_cache_valid 200 10m;
}
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_cache my_cache;
proxy_pass http://backend;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
注意:缓存命中时,limit_req 仍然生效。因为请求仍然会到达 Nginx,只是直接从缓存返回响应。
# 13. 限速与 Gzip 的交互
启用 gzip 压缩后,传输数据量减少,但压缩计算会消耗 CPU:
http {
limit_req_zone $binary_remote_addr zone=no_compress:10m rate=5r/s;
}
server {
location /large-files/ {
# 大文件下载限速
limit_rate 1024k;
limit_rate_after 50m;
# 不启用压缩(压缩大文件不划算)
gzip off;
}
location /api/ {
# API 限速,但不压缩(通常后端已经压缩)
limit_req zone=api_limit burst=10;
gzip off;
}
location /static/ {
# 静态资源:启用压缩,但不限速(CDN 负责)
gzip on;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 14. 多维度限速
有时需要同时基于多个维度限速:
方案:IP + 用户ID 组合
http {
# 基于 IP
limit_conn_zone $binary_remote_addr zone=ip_limit:10m;
# 基于用户(如果已登录)
limit_req_zone $cookie_user_id zone=user_limit:10m rate=1r/s;
}
server {
location /api/ {
# 同时限制
limit_conn addr 10;
limit_req zone=user_limit burst=5;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
生效逻辑:两个限制会叠加生效,实际限制是两者中更严格的那个。
# 15. 突发流量处理
限速配置中,burst 和 nodelay 参数决定了如何处理突发流量:
| 配置 | 行为 |
|---|---|
| 无 burst | 严格按 rate 限速 |
| burst=N | 允许最多 N 个请求排队等待 |
| burst=N nodelay | 允许最多 N 个请求立即执行,不等待 |
使用场景:
# 允许小规模突发
limit_req zone=api_limit burst=10;
# 允许大规模突发(用于营销活动等可预估的峰值)
limit_req zone=api_limit burst=100 nodelay;
2
3
4
5
风险提示:nodelay 可能导致后端瞬时压力过大,请根据后端容量合理设置。
# 16. 监控指标
部署限速后,建议监控以下指标:
- limit_req 拒绝数:
nginxlimitrejected - limit_conn 连接数:
nginxlimitconnections - zone 使用率:确保 zone 未满
- 响应时间:限速不应显著增加延迟
配置 Prometheus 采集:
location /metrics {
stub_status on;
allow 127.0.0.1;
deny all;
}
2
3
4
5
Prometheus 配置抓取 Nginx 状态,然后配合 Grafana 可视化。
# 17. 总结
Nginx 限速模块是保护后端服务的重要手段:
- 连接数限制(limit_conn):防止并发过高
- 请求频率限制(limit_req):防止请求过频
- 带宽限制(limit_rate):防止单连接占用过多带宽
配置要点:
- 根据业务流量特征选择合适的限速策略
- 合理设置 zone 大小,避免满后误杀
- 使用 burst 处理可预期的突发流量
- 配合监控及时发现异常
高级技巧:
- 基于用户身份限速
- IP 白名单
- 不同路径不同策略
- 与缓存、Gzip 等模块配合
# 18. 分布式限速
在集群环境下,单机限速不够精确,需要分布式限速方案:
方案一:Redis 共享状态
lua_shared_dict limit_dict 10m;
server {
location /api/ {
access_by_lua_block {
-- 使用 Redis 计数器实现分布式限速
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
red:connect("127.0.0.1", 6379)
local key = "limit:" .. ngx.var.remote_addr
local current = red:get(key)
if current and tonumber(current) > 100 then
ngx.exit(429)
end
red:incr(key)
red:expire(key, 1)
}
proxy_pass http://backend;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
方案二:一致性哈希
使用 consistent 选项让同一客户端始终路由到同一 upstream:
upstream backend {
consistent_hash $remote_addr;
server 192.0.2.11:8080;
server 192.0.2.12:8080;
}
2
3
4
5
# 19. 限速策略调优
根据业务类型选择策略:
| 业务类型 | 推荐策略 |
|---|---|
| 下载站 | limit_rate 限速,限制单连接带宽 |
| API 服务 | limit_req 限频率,控制 QPS |
| 登录接口 | limit_conn 限并发,防止暴力破解 |
| 文件上传 | limit_rate + 连接数限制 |
动态调整:
可以通过接口动态修改限速阈值(需要 Nginx 商业版或 Lua 脚本):
-- 通过管理接口动态调整
ngx.shared.limit_dict:set("rate", 100) -- 修改为 100r/s
2
# 20. 常见配置错误
错误:limit_conn_zone 放在 server 层
# 错误写法
server {
limit_conn_zone $binary_remote_addr zone=addr:10m; # 会在 reload 时报错
...
}
2
3
4
5
正确写法:放在 http 层。
错误:zone 大小设置过小
# 错误:1m 只能存储约 16000 个 KEY
limit_req_zone $binary_remote_addr zone=small:1m rate=10r/s;
2
正确:合理预估需要的容量
limit_req_zone $binary_remote_addr zone=addr:10m rate=10r/s; # 约 160000 个
错误:limit_rate 和 limit_req 混用不生效
limit_rate 是单连接带宽限制,limit_req 是请求频率限制,两者针对不同维度,可以同时使用。
# 21. 与 CDN 配合
如果使用 CDN,限速应在边缘节点执行:
# Nginx 只负责回源,不做限速(CDN 负责边缘限速)
upstream origin {
server 192.0.2.11:8080;
}
server {
listen 80;
server_name example.com;
# CDN 回源请求不限速
if ($http_x_cdn_ip) {
set $limit_rate 0;
}
location / {
proxy_pass http://origin;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 22. 最佳实践检查清单
部署限速前检查:
- [ ] 确认限速模块已编译进 Nginx:
nginx -V | grep limit - [ ] zone 大小足够(建议 10m+)
- [ ] limit_conn 在 http 或 server 层
- [ ] limit_rate 在 location 层
- [ ] 测试突发流量场景
- [ ] 监控 limit 拒绝数
- [ ] 白名单内部 IP 段
- [ ] 文档化限速策略
# 23. 成本考量
限速可以节省带宽成本:
| 场景 | 节省比例 |
|---|---|
| 开启 gzip | 约 70% |
| limit_rate 1Mbps(之前无限制) | 约 30-50% |
| 合理配置缓存 | 约 50%+ |
# 24. 故障恢复
当限速影响正常业务时:
- 临时关闭限速:注释掉 limit 相关配置
- 放宽阈值:增大 rate 或 burst 值
- 添加白名单:将问题 IP 加入白名单
- 回滚配置:使用版本控制回滚到上一版本
监控告警配置建议:
- 限速拒绝数 > 阈值(如每分钟 100)告警
- 限速 zone 使用率 > 80% 告警
# 25. 参考资料
- Nginx limit_conn 模块 (opens new window)
- Nginx limit_req 模块 (opens new window)
- Nginx limit_rate 模块 (opens new window)
# 26. 相关工具对比
除了 Nginx 内置模块,还有其他限速工具:
| 工具 | 类型 | 特点 |
|---|---|---|
| Nginx limit 模块 | 内置 | 简单高效,无额外组件 |
| iptables | 系统层 | 能限速整个系统 |
| tc/htb | 系统层 | 更精细的流量控制 |
| 云厂商 QoS | 云服务 | 按需付费,配置简单 |
根据实际需求选择合适的方案。