nginx限流功能的详细配置示例

# 基本概念

limit_req_zone 用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 “leaky bucket”。

limit_req_zone 参数配置
Syntax: limit_req zone=name [burst=number] [nodelay];
Default: —
Context: http, server, location


配置示例
`limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;`

第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制,"binary_"的目的是缩写内存占用量,是限制同一客户端ip地址。
第二个参数:zone=one:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息。
第三个参数:rate=10r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒10次,还可以有比如30r/m的。

配置示例
`limit_req zone=one burst=30 nodelay;`

第一个参数:zone=one 设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应。
第二个参数:burst=30,重点说明一下这个配置,burst爆发的意思,这个配置的意思是设置一个大小为5的缓冲区当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。
第三个参数:nodelay,如果设置,超过访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所有请求会等待排队。

geo 对于白名单(子网或IP都可以) 将返回0,其他IP将返回1。
map 将whiteiplist转换为 limit,如果是 $limit 是0(白名单),则返回空字符串;如果是1,则返回客户端实际IP。
limit_req_zone 限流的key不再使用 binary_remote_addr,而是limit来动态获取值。
如果是白名单,limit_req_zone 的限流key则为空字符串,将不会限流;
若不是白名单,将会对客户端真实IP进行限流。

参考使用模板配置

http {

# 限流白名单
geo $whiteiplist {
    default 1;
    127.0.0.1 0;
    192.168.100.0/24 0;
    117.159.26.211 0;
}

map $whiteiplist $limit {
    0 "";
    1 $binary_remote_addr;
}

# 定义请求限流zone(基于客户端IP)
# $binary_remote_addr:用二进制格式存储客户端IP,节省空间
# zone=req_limit:10m:创建名为req_limit的共享内存区,10MB大小
# rate=10r/s:限制每秒10个请求(也可以用r/m表示分钟)
#limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;

limit_req_zone $limit  zone=req_limit:10m rate=10r/s;

# 定义连接数限制zone
# zone=conn_limit:10m:创建名为conn_limit的共享内存区
#limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

limit_conn_zone $limit zone=conn_limit:10m; 

server {
    listen 80;
    server_name example.com;

    # 应用请求限流
    # zone=req_limit:使用前面定义的限流zone
    # burst=20:允许突发20个请求排队
    # nodelay:不延迟处理突发请求(立即扣减burst计数)
    
    limit_req zone=req_limit burst=20 nodelay;

    # 应用连接数限制
    # 每个IP同时最多保持20个连接
    limit_conn conn_limit 20;

    # 可选:对特定URI做更严格的限制
    location /api/ {
        limit_req zone=req_limit burst=5;
        limit_conn conn_limit 5;
    }

}

}


# 一、基础限流配置

## 1. 连接数限制(ngx_http_limit_conn_module)

http {

定义共享内存区(10MB空间,存储连接状态)

limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

server {
listen 80;
server_name example.com;

# 全局限流(单个IP最大并发连接数)
limit_conn conn_limit 50;  # 限制每个IP最多50个并发连接

location / {
  proxy_pass http://backend;
}

# 特殊路径单独限流
location /api/sensitive {
  limit_conn conn_limit 10;  # 敏感接口更严格限制
}

}
}


说明:
`zone=conn_limit:10m:分配10MB内存存储IP请求状态,约支持16万独立IP。`

## 2. 请求速率限制(ngx_http_limit_req_module)

http {

定义速率限制区(10MB空间,存储请求状态)

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; # 全局限速10请求/秒

server {
listen 80;
server_name api.example.com;

location /api/ {
  # 基础速率限制
  limit_req zone=api_limit burst=20 nodelay;  # 突发20请求,不延迟处理

  # 组合连接数限制
  limit_conn conn_limit 20;

  proxy_pass http://backend_api;
}

}
}

说明:
`rate=10r/s:限制每个IP每秒最多10个请求。`
`burst=20:允许突发20个请求进入队列,避免误伤正常用户。`
`nodelay:直接处理队列中的请求(无延迟),若需平滑限流可移除该参数。`


# 二、高级限流场景

## 1. 分层限流策略

http {

定义多层限流区

limit_req_zone $binary_remote_addr zone=global_limit:10m rate=100r/s; # 全局限速
limit_req_zone $server_name zone=server_limit:10m rate=50r/s; # 服务器级限速

server {
listen 80;
server_name pay.example.com;

location /payment/ {
  # 多层限流叠加
  limit_req zone=global_limit burst=50;
  limit_req zone=server_limit burst=30;

  # 最终生效规则:min(100r/s, 50r/s) = 50r/s,突发队列总长度80
  proxy_pass http://payment_backend;
}

}
}


## 2. 动态限流(需Nginx Plus)

http {

基于服务状态的动态限流

limit_req_status 503; # 自定义限流响应码

limit_req_zone $binary_remote_addr zone=dynamic_limit:10m rate=5r/s;

server {
listen 80;
server_name dynamic.example.com;

location / {
  # 结合服务健康度动态调整限流阈值
  limit_req zone=dynamic_limit 
            burst=10 
            nodelay 
            window=2s;  # 滑动窗口时间范围

  proxy_pass http://backend_service;
  health_check;       # 需配合Nginx Plus健康检查
}

}
}


## 3. 地理围栏限流

http {

定义地理限流区(需GeoIP模块)

map $geoip_country_code $allowed_country {
default no;
CN yes;
US yes;
}

limit_req_zone $binary_remote_addr zone=geo_limit:10m rate=5r/s;

server {
listen 80;
server_name global.example.com;

location / {
  if ($allowed_country = no) {
    limit_req zone=geo_limit burst=2 nodelay;  # 非允许国家更严格限流
  }

  proxy_pass http://global_backend;
}

}
}


# 三、监控与调试配置
## 1. 实时状态监控

http {
server {
listen 8080;
server_name status.example.com;

location /limit_status {
  # 自定义限流状态页(需Lua模块)
  content_by_lua_block {
    local zone = ngx.shared.api_limit
    ngx.say("Active requests: ", zone.active)
    ngx.say("Rejected requests: ", zone.rejected)
  }
  allow 192.168.1.0/24;
  deny all;
}

}
}


## 2. 详细日志记录

http {
log_format限流日志 '$remote_addr - \(remote_user [\)time_local] '
'"$request" $status \(body_bytes_sent ' '"\)http_referer" "\(http_user_agent" ' '\)limit_rate \(limit_conn ' # 记录限流状态,好像不管用,nginx配置文件检测报错 '\)upstream_response_time';
access_log /var/log/nginx/limit_access.log限流日志;
}


# 四、性能调优建议

内存优化
共享内存区大小计算公式:预估并发用户数 × (记录大小 + 指针大小)
典型记录大小:IPv4约32字节,IPv6约128字节
突发处理
burst参数应设置为平均速率 × 突发时间窗口(例如:100r/s × 5s = 500)
结合nodelay参数实现立即处理突发请求
滑动窗口优化
使用window参数替代默认漏桶算法(需Nginx 1.19+)
示例:limit_req zone=name rate=10r/s window=2s; 实现2秒内10请求的平滑限制


# 五、安全加固方案
## 1. 组合防护配置

http {

定义多层防护区

limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=20r/s;

server {
listen 443 ssl;
server_name secure.example.com;

location /api/v1/ {
  # 连接数限制
  limit_conn conn_zone 30;

  # 请求速率限制
  limit_req zone=req_zone burst=50 nodelay;

  proxy_pass http://secure_backend;
}

}
}


## 2. 自动封禁配置(需Fail2ban)

/etc/fail2ban/jail.local

[DEFAULT]
bantime = 1h # 封禁时间(1 小时)
findtime = 10m # 查找时间窗(10 分钟)
maxretry = 5 # 最大失败次数(超出则封禁)

[nginx-limit-req]
enabled = true
port = http,https
logpath = %(nginx_error_log)s # nginx默认错误日志路径:/var/log/nginx/error.log

[nginx-http-auth]
mode = normal
enabled = true
port = http,https
logpath = %(nginx_error_log)s

[nginx-botsearch]
enabled = true
port = http,https
logpath = %(nginx_error_log)s

[nginx-bad-request]
enabled = true
port = http,https
logpath = %(nginx_access_log)s

[nginx-forbidden]
enabled = true
port = http,https
logpath = %(nginx_error_log)s


## 六、配置验证与测试
- 语法检查

`nginx -t -c /etc/nginx/nginx.conf`

- 压力测试

使用wrk进行限流测试

wrk -t4 -c100 -d30s --latency http://api.example.com/api/


- 实时监控

观察限流计数器

watch -n1 "nginx -s limit_status"

分析访问日志

awk '/limit_conn/ || /limit_req/' /var/log/nginx/access.log


# 七、最佳实践建议

分级限流策略
基础层:全局限速(防止DDoS)
业务层:接口级限速(保护核心服务)
用户层:单个用户限速(防止刷接口)
动态调整机制
结合Prometheus监控指标,通过API动态修改限流阈值
示例:使用ngx_http_lua_module实现动态配置加载
容灾设计
配置limit_req_status 503返回自定义错误页
结合proxy_next_upstream实现服务降级


通过合理配置限流策略,可有效防御DDoS攻击、保护后端服务、维护系统稳定性。实际部署时建议通过全链路压测确定阈值,并结合业务增长情况定期调整限流参数。
posted @ 2025-06-25 15:55  哈喽哈喽111111  阅读(529)  评论(0)    收藏  举报