Nginx限流配置:防止接口被刷,服务器稳如泰山

你有没有遇到过这些情况?

  • 凌晨三点收到报警,登录接口被暴力破解,服务器CPU飙到80%

  • 短信验证码接口被刷,一夜之间损失几千块

  • 网站资源被爬虫疯狂抓取,带宽被占满,正常用户打不开页面

  • 大文件下载接口被人恶意刷,服务器流量费用暴涨

这些问题,本质上都是:有人在恶意刷你的接口。

你当然可以自己写限流代码,但要考虑并发、内存、分布式......很麻烦。

今天介绍 Nginx 的一个内置模块------限流(ngx_http_limit_req_module)。

它可以直接在流量入口做限流,不侵入业务代码,配置简单,性能极高。完全不用后端自己写限流代码,Nginx 本身就提供了非常优秀的限流功能。

一、什么时候需要限流

场景 问题 限流目标
登录接口 暴力破解密码 每秒1次
短信验证码 短信轰炸,一夜损失几千块 每分钟1次
公开API 爬虫抓取、恶意刷接口 每秒10-100次
大文件下载 耗尽带宽,影响其他人 每秒2-5次
秒杀/抢购 瞬间流量打爆服务器 每秒限制,超出排队
管理后台 误操作、恶意扫描 每秒30次

记住:处理越慢的接口,限流要越严。

二、核心参数说明

限流配置分两步:

复制代码
# 第一步:定义规则(放在 http 块)
limit_req_zone $binary_remote_addr zone=名字:10m rate=10r/s;

# 第二步:应用规则(放在 location 块)
limit_req zone=名字 burst=20 nodelay;

参数解读:

参数 含义 说明
$binary_remote_addr 按客户端IP限流 每个人单独计数
zone=名字:10m 内存区名称和大小 10m约存15-30万个IP
rate=10r/s 限流速率 每秒10次,超出的拦截
burst=20 突发缓冲队列 瞬间超出时先排队,不直接拒绝
nodelay 不排队 超出burst的请求立即返回503

rate 单位:

单位 含义 适合场景
r/s 每秒请求数 登录、API、下载
r/m 每分钟请求数 短信验证码、注册

三、按场景配置模板

场景1:登录接口防暴力破解

每秒1次,允许瞬间3次,超出直接拒绝。

复制代码
http {
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

    server {
        location /api/login {
            limit_req zone=login burst=3 nodelay;
            proxy_pass http://backend;
        }
    }
}

场景2:短信验证码防轰炸

每分钟1次,不允许突发。

复制代码
http {
    limit_req_zone $binary_remote_addr zone=sms:10m rate=1r/m;

    server {
        location /api/sms {
            limit_req zone=sms burst=1 nodelay;
            proxy_pass http://backend;
        }
    }
}

场景3:公开API防爬虫

每秒10次,允许20次突发,超出排队(不直接拒绝,避免影响体验)。

复制代码
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=api burst=20;   # 没有 nodelay,请求会排队
            proxy_pass http://backend;
        }
    }
}

场景4:下载/导出接口限流

每秒2次,允许5次突发。

复制代码
http {
    limit_req_zone $binary_remote_addr zone=download:10m rate=2r/s;

    server {
        location /download/ {
            limit_req zone=download burst=5 nodelay;
            alias /var/www/downloads/;
        }
    }
}

场景5:完整生产配置(多接口不同限流)

复制代码
http {
    # 定义三个级别的限流规则
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
    limit_req_zone $binary_remote_addr zone=sms:10m rate=1r/m;

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            proxy_pass http://backend;
        }
        
        location /api/login {
            limit_req zone=login burst=3 nodelay;
            proxy_pass http://backend;
        }
        
        location /api/sms {
            limit_req zone=sms burst=1 nodelay;
            proxy_pass http://backend;
        }
        
        location /health {
            access_log off;
            return 200 "OK\n";
        }
    }
}

四、内网IP怎么不限流?

监控系统、公司办公网不应该被限流。用白名单:

复制代码
http {
    geo $whitelist {
        default 0;
        127.0.0.1 1;
        192.168.0.0/16 1;
        10.0.0.0/8 1;
    }
    
    map $whitelist $limit_key {
        0 $binary_remote_addr;
        1 "";
    }
    
    limit_req_zone $limit_key zone=api:10m rate=10r/s;

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

五、配完怎么验证?

方法1:用ab压测

复制代码
sudo apt install apache2-utils -y
ab -c 10 -n 20 http://your-server/api/test

关注输出:

复制代码
Failed requests:        19
Non-2xx responses:      19

失败数越高,限流生效越明显。

方法2:看Nginx错误日志

复制代码
sudo tail -f /var/log/nginx/error.log | grep limiting

被限流时会输出:

复制代码
limiting requests, excess: 1.000 by zone "login", client: 192.168.1.100

附:我们今天的测试过程

好的,把原来较长的测试过程压缩成这个精简版:


附:测试验证过程

配置写完后,我用 ab -c 10 -n 20 压测------所有请求全部通过

检查配置、重装 Nginx、换 CentOS,限流还是没生效。我开始怀疑模块是不是假的。

排查了几个小时后,忽然闪过一个念头:会不会是响应太快了?

我当时用的是 return 200,Nginx 直接返回,微秒级就处理完了。限流还没来得及生效,请求已经跑完了。

于是我写了一个简单的 Python 后端,每次请求先 sleep 0.4 秒:

复制代码
@app.route('/api/test')
def test():
    time.sleep(0.4)
    return "OK\n"

再用同样的命令压测------

限流出来了。 错误日志也出现了 limiting requests

结论:不是限流没生效,是测试方式不对。return 测限流,车太快,摄像头拍不到。


这个版本保留了完整的排查逻辑链,但篇幅压缩到原来的1/3左右,更紧凑。

六、常见问题

现象 可能原因 解决方法
压测全部通过 后端响应太快(如直接用return 换成代理到真实后端,或加下载文件测试
日志没有limiting 限流规则没生效 检查limit_req_zone是否在http块内
内网IP也被限流 没配白名单 用白名单配置
正常用户被误伤 rate或burst太严格 先设宽松值,观察后再收紧

七、生产建议

建议 说明
先宽松后收紧 先用rate=100r/s观察正常流量,再逐步调低
白名单必配 内网IP、监控系统、公司出口IP不要限流
自定义503页面 被限流时返回友好提示
配合监控告警 发现大量503及时调整
相关推荐
繁星星繁4 分钟前
自动化构建-make/Makefile
运维·自动化
你是个什么橙4 分钟前
安装KVM服务器、使用libvirt tools工具管理虚拟机
运维·服务器·云计算
锋行天下5 分钟前
中小项目高可用,真的需要K8s吗?从单机备份到企业级架构的完整思考
后端·mysql·nginx
.千余9 分钟前
【C++】 String 常用操作:增删查改 | 查找 | 截取 | IO
java·服务器·开发语言·c++·笔记·学习
RisunJan16 分钟前
Linux命令-parted(磁盘分区工具)
linux·运维
艾莉丝努力练剑23 分钟前
【QT】界面优化:QSS
linux·运维·开发语言·网络·qt·计算机网络·udp
一只积极向上的小咸鱼23 分钟前
TOML、JSON、YAML、INI 配置文件格式总结
java·服务器·json
岭锅锅24 分钟前
机房磁控U位资产管理系统:让数据中心资产管理告别粗放式运维
运维·机房·数据机房管理
C137的本贾尼24 分钟前
磁盘结构与关键日志:Redo Log、Undo Log 与双写缓冲区
服务器·数据库·oracle
煜36429 分钟前
进程控制知识
linux·运维·服务器