15-限流防刷配置:接口限流、IP限流、防恶意请求、保护SaaS后台

15-限流防刷配置:接口限流、IP限流、防恶意请求、保护SaaS后台

前言

做SaaS平台最怕什么?不是bug,是被人刷。你的售货柜SaaS后台API刚上线,竞争对手写个脚本疯狂调你的设备状态查询接口,QPS飙到5000,数据库连接池瞬间耗尽,正常用户全超时。又或者有人拿脚本批量尝试扫码开门,一天刷你几十万次请求。这些问题的第一道防线不在代码里,在Nginx。这篇就把Nginx限流配置从原理到实战讲清楚。

一、Nginx限流模块:两个核心指令

1.1 limit_req ------ 请求速率限流

limit_req 基于漏桶算法 ,控制每个KEY的请求速率。需要先用 limit_req_zone 定义限流区,再用 limit_req 启用。

nginx 复制代码
# http块中定义限流区
http {
    # 参数1:KEY(按IP限流)
    # 参数2:共享内存区名称和大小(10m约存16万个IP)
    # 参数3:速率(每秒10个请求)
    limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s;
}
nginx 复制代码
# server/location块中启用
location /api/ {
    limit_req zone=req_limit burst=20 nodelay;
    proxy_pass http://backend;
}

参数详解

参数 含义 示例
zone 引用的限流区名称 req_limit
burst 突发请求队列长度 20(允许20个请求排队)
nodelay 队列中的请求立即处理不等待 有burst时建议加
delay 延迟处理前N个突发请求 delay=5

1.2 limit_conn ------ 并发连接数限流

limit_conn 限制同一KEY同时持有的连接数,防止单IP开大量并发连接打满服务器。

nginx 复制代码
http {
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}

server {
    location /api/ {
        limit_conn conn_limit 10;  # 每个IP最多10个并发连接
        proxy_pass http://backend;
    }
}

区别limit_req 管"频率"(每秒几次),limit_conn 管"并发"(同时几个连接)。两个配合用才全面。

二、漏桶算法与令牌桶算法原理

2.1 漏桶算法(Nginx limit_req 的基础)

markdown 复制代码
       请求流入
         ||
         vv
    ┌──────────┐
    │  漏 桶   │  ← burst(桶容量)
    │~~~~~~~~~~│
    │  存储    │
    └────┬─────┘
         │  恒定速率漏出(rate)
         vv
      后端处理

核心思想:请求像水一样倒入桶中,桶以恒定速率漏水。水满(超过burst)则丢弃。保证后端处理速率恒定。

  • rate=10r/s:每秒漏出10个请求(每100ms处理一个)
  • burst=20:桶能暂存20个突发请求
  • nodelay:桶里的请求不排队等待,立即放行(但仍然消耗桶容量)

2.2 令牌桶算法

markdown 复制代码
    定速生成令牌 → ┌──────────┐
                   │  令牌桶   │  ← 桶容量
                   │  tokens  │
                   └────┬─────┘
                        │
    请求到达 → 取令牌 → 有令牌则通过,无令牌则拒绝

核心思想:系统以恒定速率往桶里放令牌,请求来了取一个令牌,取不到就拒绝。允许一定程度的突发(桶里有积攒的令牌)。

两者区别

维度 漏桶 令牌桶
突发流量 严格限制(超过burst丢弃) 允许突发(有令牌就能过)
输出速率 恒定 可变(取决于令牌存量)
Nginx支持 limit_req原生支持 需Lua实现
适用场景 保护后端不被打垮 允许短时突发流量

2.3 nodelay参数深入理解

不加 nodelay 时,burst队列中的请求会按rate速率延迟处理:

diff 复制代码
请求来了30个,rate=10r/s,burst=20:
- 前10个立即处理
- 后20个进入burst队列,每100ms放行一个
- 第21个之后的请求直接返回503

加了 nodelay

diff 复制代码
请求来了30个,rate=10r/s,burst=20,nodelay:
- 前30个(10+20)立即处理
- 但burst桶被消耗,后续请求需要等桶恢复
- 超过30的请求直接返回503

生产建议 :大多数场景用 nodelay,体验更好。如果后端确实扛不住瞬时并发,去掉 nodelay 让Nginx帮你匀速。

三、接口级别限流实战

3.1 不同接口不同限流策略

售货柜SaaS后台有不同的接口类型,限流策略应有所区分:

nginx 复制代码
http {
    # 按IP限流 - 普通查询接口
    limit_req_zone $binary_remote_addr zone=api_normal:10m rate=20r/s;

    # 按IP限流 - 写操作接口(更严格)
    limit_req_zone $binary_remote_addr zone=api_write:10m rate=5r/s;

    # 按IP限流 - 登录接口(最严格,防暴力破解)
    limit_req_zone $binary_remote_addr zone=api_login:10m rate=1r/s;

    # 按IP限流 - 设备控制接口(开门、出货)
    limit_req_zone $binary_remote_addr zone=api_device:10m rate=2r/s;

    # 连接数限流
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    # 限流时返回429而非默认503
    limit_req_status 429;
    limit_conn_status 429;
}
nginx 复制代码
server {
    listen 80;
    server_name api.alspd.com;

    # 全局并发连接限制
    limit_conn conn_limit 20;

    # 普通查询接口 - 20r/s,允许突发10个
    location /api/device/list {
        limit_req zone=api_normal burst=10 nodelay;
        proxy_pass http://backend;
    }

    location /api/device/status {
        limit_req zone=api_normal burst=10 nodelay;
        proxy_pass http://backend;
    }

    # 写操作接口 - 5r/s
    location /api/device/update {
        limit_req zone=api_write burst=3 nodelay;
        proxy_pass http://backend;
    }

    # 登录接口 - 1r/s,防暴力破解
    location /api/auth/login {
        limit_req zone=api_login burst=2 nodelay;
        proxy_pass http://backend;
    }

    # 设备控制接口 - 2r/s,防恶意开门
    location /api/device/control {
        limit_req zone=api_device burst=1 nodelay;
        proxy_pass http://backend;
    }
}

3.2 按用户ID限流

IP限流有局限:企业用户走同一个出口IP,按IP限流会误伤。可以按用户ID限流:

nginx 复制代码
http {
    # 按用户ID限流(从JWT中提取,需配合Lua或后端设置header)
    limit_req_zone $http_x_user_id zone=user_limit:10m rate=30r/s;
}

location /api/ {
    limit_req zone=user_limit burst=20 nodelay;
    proxy_pass http://backend;
}

后端在请求头中设置 X-User-Id,Nginx按用户ID进行限流。注意:此方案要求后端在Nginx之前做鉴权,或者用Nginx + Lua从JWT中解析用户ID。

3.3 多维度组合限流

同时按IP和用户ID限流,双重保护:

nginx 复制代码
location /api/ {
    # IP维度:单IP 30r/s
    limit_req zone=api_normal burst=10 nodelay;
    # 用户维度:单用户 20r/s
    limit_req zone=user_limit burst=5 nodelay;
    # 并发连接:单IP最多20个
    limit_conn conn_limit 20;

    proxy_pass http://backend;
}

优先级:Nginx会同时检查所有limit规则,任何一个触发限流就返回429。

四、白名单IP排除限流

4.1 地理白名单

内网管理服务器、监控探针不应被限流。用 geo 模块定义白名单:

nginx 复制代码
http {
    # 定义白名单IP段
    geo $limit_ip {
        default 1;              # 默认需要限流
        127.0.0.1 0;            # 本地不限流
        192.168.0.0/16 0;       # 内网不限流
        10.0.0.0/8 0;           # 内网不限流
        172.16.0.0/12 0;        # 内网不限流
        # 运维办公IP
        116.236.xxx.xxx 0;
        # 第三方合作方IP
        121.40.xxx.xxx 0;
    }

    # 利用map将白名单IP的KEY设为空字符串,实现跳过限流
    map $limit_ip $limit_key {
        0 "";                   # 白名单:KEY为空,不参与限流
        1 $binary_remote_addr;  # 非白名单:KEY为IP,参与限流
    }

    # 使用动态KEY定义限流区
    limit_req_zone $limit_key zone=api_limit:10m rate=20r/s;
    limit_conn_zone $limit_key zone=conn_limit:10m;
}

location /api/ {
    limit_req zone=api_limit burst=10 nodelay;
    limit_conn conn_limit 20;
    proxy_pass http://backend;
}

原理 :白名单IP的 $limit_key 为空字符串,Nginx对空KEY的请求不做限流计数。这是官方推荐的白名单实现方式。

五、防DDoS基础防护

5.1 连接数封顶

nginx 复制代码
http {
    # 全局连接数限制
    limit_conn_zone $binary_remote_addr zone=ddos_conn:10m;
}

server {
    # 单IP全局最多50个并发连接
    limit_conn ddos_conn 50;

    # 单个location更严格
    location /api/ {
        limit_conn ddos_conn 20;
        proxy_pass http://backend;
    }
}

5.2 请求体大小限制

DDoS常通过发送超大请求体消耗带宽:

nginx 复制代码
http {
    # 全局默认限制1MB
    client_max_body_size 1m;
    client_body_buffer_size 16k;
}

# 只在需要上传的接口放开
location /api/upload/ {
    client_max_body_size 50m;
    proxy_pass http://backend;
}

5.3 限制请求方法

只允许必要的HTTP方法,拒绝TRACE、DELETE等:

nginx 复制代码
location /api/ {
    # 只允许GET/POST/PUT
    limit_except GET POST PUT {
        deny all;
    }
    proxy_pass http://backend;
}

5.4 自动封禁高频IP(配合Lua)

nginx 复制代码
access_by_lua_block {
    local limit = require "resty.limit.req"
    -- 每秒100次请求的IP直接拉黑
    local lim = limit.new("ddos_block", 100, 100)
    local delay, err = lim:incoming(ngx.var.binary_remote_addr, true)
    if not delay then
        if err == "rejected" then
            -- 记录到共享内存,后续请求直接拒绝
            local block_list = ngx.shared.block_list
            block_list:set(ngx.var.binary_remote_addr, 1, 3600)  -- 封禁1小时
            ngx.exit(403)
        end
    end

    -- 检查是否在封禁列表中
    local block_list = ngx.shared.block_list
    if block_list:get(ngx.var.binary_remote_addr) then
        ngx.exit(403)
    end
}

六、无人售货柜SaaS后台完整限流配置

nginx 复制代码
# /etc/nginx/conf.d/saas-api.conf

http {
    # ========== 限流区定义 ==========

    # 白名单
    geo $limit_ip {
        default 1;
        127.0.0.1 0;
        192.168.0.0/16 0;
        10.0.0.0/8 0;
    }

    map $limit_ip $limit_key {
        0 "";
        1 $binary_remote_addr;
    }

    # 按IP限流
    limit_req_zone $limit_key zone=api_read:10m rate=20r/s;
    limit_req_zone $limit_key zone=api_write:10m rate=5r/s;
    limit_req_zone $limit_key zone=api_login:10m rate=1r/s;
    limit_req_zone $limit_key zone=api_device:10m rate=3r/s;
    limit_req_zone $limit_key zone=api_upload:10m rate=1r/s;

    # 连接数限流
    limit_conn_zone $limit_key zone=conn_limit:10m;

    # 限流状态码
    limit_req_status 429;
    limit_conn_status 429;
}

server {
    listen 443 ssl http2;
    server_name api.alspd.com;

    # 全局配置
    client_max_body_size 1m;
    limit_conn conn_limit 30;

    # ========== 登录认证接口 ==========
    location /api/auth/login {
        limit_req zone=api_login burst=2 nodelay;
        limit_conn conn_limit 5;
        proxy_pass http://backend;
    }

    location /api/auth/refresh {
        limit_req zone=api_login burst=2 nodelay;
        proxy_pass http://backend;
    }

    # ========== 设备查询接口(读操作) ==========
    location /api/device/list {
        limit_req zone=api_read burst=20 nodelay;
        proxy_pass http://backend;
    }

    location /api/device/status {
        limit_req zone=api_read burst=20 nodelay;
        proxy_pass http://backend;
    }

    location /api/order/list {
        limit_req zone=api_read burst=20 nodelay;
        proxy_pass http://backend;
    }

    # ========== 设备控制接口(高敏感) ==========
    location /api/device/control {
        limit_req zone=api_device burst=1 nodelay;
        limit_conn conn_limit 2;
        proxy_pass http://backend;
    }

    location /api/device/door/open {
        limit_req zone=api_device burst=1 nodelay;
        limit_conn conn_limit 1;
        proxy_pass http://backend;
    }

    # ========== 写操作接口 ==========
    location /api/device/update {
        limit_req zone=api_write burst=3 nodelay;
        proxy_pass http://backend;
    }

    location /api/order/refund {
        limit_req zone=api_write burst=2 nodelay;
        proxy_pass http://backend;
    }

    # ========== 文件上传接口 ==========
    location /api/upload/ {
        client_max_body_size 50m;
        limit_req zone=api_upload burst=1 nodelay;
        limit_conn conn_limit 2;
        proxy_pass http://backend;
    }

    # ========== 限流响应 ==========
    error_page 429 = @rate_limited;

    location @rate_limited {
        default_type application/json;
        return 429 '{"code":429,"message":"请求过于频繁,请稍后再试"}';
    }
}

七、限流效果验证

7.1 压测验证

bash 复制代码
# 用ab压测,模拟并发请求
ab -n 100 -c 20 -H "Authorization: Bearer xxx" https://api.alspd.com/api/device/list

# 观察返回结果:
# - 部分请求返回200(正常处理)
# - 超过限流的返回429

7.2 查看限流统计

bash 复制代码
# 查看Nginx错误日志中的限流记录
tail -f /var/log/nginx/error.log | grep "limiting requests"

# 输出示例:
# limiting requests, excess: 20.1 by zone "api_read"

7.3 自定义限流日志

nginx 复制代码
log_format limit_log '$remote_addr - $time_local - '
                     'zone=$limit_req_zone - excess=$limit_req_excess';

location /api/ {
    limit_req zone=api_read burst=10 nodelay;
    access_log /var/log/nginx/limit.log limit_log;
    proxy_pass http://backend;
}

总结

Nginx限流三板斧:limit_req(请求速率)、limit_conn(并发连接数)、geo + map(白名单排除)。核心思路是按接口敏感程度分级限流------登录接口最严(1r/s)、设备控制次之(2~3r/s)、普通查询宽松(20r/s)。生产环境务必组合使用IP维度和用户维度限流,配合白名单排除内网和合作方IP。限流不是一刀切,是让你的系统在流量洪峰下还能稳稳服务正常用户。

相关推荐
AI服务老曹1 小时前
AI视频分析私有化验收性能优化指南:从资源瓶颈排查到运维交接
人工智能·性能优化·音视频
云物互联1 小时前
企业垂类智能体的 Harness 工程:从第一性原理到架构设计
人工智能
greasyfork1 小时前
Ps 2026 v27.6 For Mac:专业图像处理工作流解析
图像处理·人工智能·macos·ps
饼干哥哥1 小时前
保姆级教程|Codex接入 DeepSeek、Kimi K3后,天下无对手!
人工智能·深度学习·ai编程
Mr数据杨1 小时前
【CanMV K210】系统环境 IDE 连接开发板与串口通信
人工智能·硬件开发·canmv k210
tedcloud1231 小时前
diagram-design 怎么安装?用 AI 自动生成更专业的架构图、流程图
linux·运维·前端·人工智能·开源·流程图
zzz海羊1 小时前
2026全平台移动办公远控助手横测:从鸿蒙到工作站,ToDesk、向日葵、TeamViewer、AnyDesk谁更适配?
人工智能·华为·agent·harmonyos·teamviewer
故七月1 小时前
AI 搜索重构信息分发逻辑:2026年企业 GEO 布局现状与行业演进分析
大数据·人工智能
benchmark_cc1 小时前
Claude Code + MCP + QuantDash:打造全自动量化研究流水线的终极指南
人工智能·后端·爬虫·算法·claude·mcp·quantdash