Nginx是如何实现限流和黑名单拦截的?

你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。

点击下方👇关注公众号,带你一起复习后端技术,看看面试考点,补充积累技术知识,每天都为面试准备积累

文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读


在Nginx中实现限流和黑名单拦截是保障服务稳定的重要手段,以下是 4种核心方案 的详细实现步骤和配置示例:


01
请求频率限流(令牌桶算法)


配置原理:通过ngx_http_limit_req_module模块实现

# http块定义限流规则http {    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;        server {        location /api/ {            limit_req zone=api_limit burst=20 nodelay;            proxy_pass http://backend;                        # 触发限流时的响应(默认返回503)            limit_req_status 429;        }    }}

参数解析:

  • zone=api_limit:10m:定义10MB内存区存储访问状态

  • rate=10r/s:每秒允许10个请求(实际按毫秒平滑处理)

  • burst=20:允许突发20个请求排队

  • nodelay:不延迟处理突发请求


02
并发连接数限制


配置原理:通过ngx_http_limit_conn_module模块实现

http {    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;    server {        location /download/ {            limit_conn conn_limit 5;  # 单IP最大5并发连接            limit_rate_after 10m;    # 下载10MB后限速            limit_rate 100k;          # 限速到100KB/s        }    }}
03
静态IP黑名单拦截


方案1:配置文件直接拒绝

# 在http/server/location块中添加deny 192.168.1.100;     # 拒绝单个IPdeny 10.0.0.0/8;        # 拒绝整个网段allow 172.16.0.0/16;    # 白名单优先于黑名单allow all;               # 允许其他所有IP

方案2:动态黑名单(需安装Lua模块)

http {    lua_shared_dict blacklist 10m; # 共享内存存储黑名单    server {        location / {            access_by_lua_block {                local blacklist = ngx.shared.blacklist                local client_ip = ngx.var.remote_addr                                if blacklist:get(client_ip) then                    ngx.exit(ngx.HTTP_FORBIDDEN) # 返回403                end            }        }        # 动态添加黑名单的接口(需做权限控制)        location /admin/blacklist {            content_by_lua_block {                local ip = ngx.req.get_uri_args()["ip"]                ngx.shared.blacklist:set(ip, true, 3600) # 封禁1小时                ngx.say("已封禁IP: "..ip)            }        }    }}
04
动态自动封禁(基于请求特征)


示例:1分钟内请求超过100次自动封禁

http {    limit_req_zone $binary_remote_addr zone=auto_block:10m rate=100r/m;    server {        location / {            limit_req zone=auto_block burst=150;            error_page 503 @blacklist;        }        location @blacklist {            # 触发限流时记录到黑名单            access_by_lua_block {                local blacklist = ngx.shared.blacklist                local client_ip = ngx.var.remote_addr                blacklist:set(client_ip, true, 600) # 封禁10分钟                ngx.exit(503)            }        }    }}
05
高级防火墙集成方案


使用fail2ban + Nginx日志分析

1. 安装配置fail2ban:

# 安装sudo apt-get install fail2ban# 创建Nginx规则配置文件/etc/fail2ban/jail.d/nginx.conf


2.配置监控规则:

[nginx-limit-req]enabled = truefilter = nginx-limit-reqaction = iptables[name=HTTP, port=http, protocol=tcp]logpath = /var/log/nginx/error.logmaxretry = 3      # 触发阈值findtime = 300    # 5分钟内bantime = 3600    # 封禁1小时


3.创建过滤规则:

/etc/fail2ban/filter.d/nginx-limit-req.conf[Definition]failregex = limiting requests, excess:.*client: <HOST>


验证配置效果

1.压力测试工具:

# 测试并发请求ab -n 1000 -c 50 http://your-domain.com/api/# 测试单IP高频访问siege -c 10 -t 1M http://your-domain.com/login


2.查看黑名单状态:

# 查看Nginx共享内存中的黑名单nginx -c /path/to/nginx.conf -t 2>&1 | grep blacklist# 查看iptables封禁列表iptables -L -n


06
完整配置示例


# 黑名单管理geo $blacklist {    default 0;    include /etc/nginx/conf.d/blacklist.conf; # IP列表文件}# 限流配置limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;limit_conn_zone $binary_remote_addr zone=conn_limit:10m;server {    listen 80;        # 黑名单拦截    if ($blacklist) {        return 444; # 直接关闭连接    }    location /api/ {        limit_req zone=api_limit burst=200 nodelay;        limit_conn conn_limit 50;        proxy_pass http://api_backend;    }    location /admin/ {        allow 192.168.1.0/24; # 只允许内网访问        deny all;    }}


关键注意事项

  • 灰度发布:新规则应先在小流量环境验证

  • 监控报警:配合Prometheus + Grafana监控限流触发情况

  • 防御穿透:针对代理IP(X-Forwarded-For)需特殊处理

  • 性能影响:共享内存大小需根据业务规模调整(1MB≈8000个IP)


以上方案可根据实际业务需求组合使用,建议从简单静态规则开始逐步升级到动态智能防护。

今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!

END


扫码关注

一起积累后端知识
不积跬步,无以至千里
不积小流,无以成江海

喜欢此内容的人还喜欢

《Java面试题指南》回归啦~


一个阿里二面面试官必问的问题


Lambda表达式说爱你不容易


分享面试:mysql数据库索引失效的情况


Spring-Boot中一个不起眼的好工具StopWatch