0%

Nginx配置限流

Nginx 配置限流:基于漏桶算法的流量控制策略

在高并发场景中,突发流量可能导致服务器过载、响应延迟甚至崩溃。Nginx 提供了基于漏桶算法的限流功能,通过limit_req_zonelimit_req指令控制请求速率,保护后端服务稳定。本文详细讲解 Nginx 限流的配置方法、核心参数及实战场景,帮助合理管控流量。

限流核心原理:漏桶算法

Nginx 限流基于漏桶算法(Leaky Bucket),其核心逻辑如下:

  • 想象一个 “漏桶”,请求如同水流注入桶中,桶底有一个固定速率的 “漏洞”;
  • 若请求注入速度超过漏洞的漏水速度,多余的水(请求)会溢出(被拒绝);
  • 通过控制漏洞的速率(rate)和桶的容量(burst),实现请求的匀速处理,避免瞬间压力。

基础配置:limit_req_zonelimit_req

Nginx 限流需两步配置:先在http块定义限流规则(limit_req_zone),再在location/server块应用规则(limit_req)。

定义限流区域(limit_req_zone

1
2
3
4
5
6
7
http {
# 定义限流规则
# $binary_remote_addr:以客户端IP的二进制形式作为key(节省内存)
# zone=mylimit:1m:创建名为mylimit的共享内存区域,大小1M(约可存储16000个IP状态)
# rate=1r/m:限制速率为每分钟1个请求(r/s表示每秒,r/m表示每分钟)
limit_req_zone $binary_remote_addr zone=mylimit:1m rate=1r/m;
}
  • 参数说明:
    • key:用于区分请求的标识(如$binary_remote_addr按 IP 限流,$request_uri按 URL 限流);
    • zone:定义共享内存区域(多 Worker 进程共享状态,确保计数准确);
    • rate:请求速率上限(格式为N r/sN r/m,如10r/s表示每秒最多 10 个请求)。

应用限流规则(limit_req

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
server_name example.com;

location /api {
# 应用名为mylimit的限流规则
# burst=10:允许10个请求排队等待
# nodelay:队列中的请求不延迟,立即处理(超出burst的请求被拒绝)
limit_req zone=mylimit burst=10 nodelay;

# 转发到后端服务
proxy_pass http://backend;
}
}

核心参数详解

1. burst:排队缓冲大小

burst定义允许临时超出rate的请求数量(即 “漏桶” 的容量)。例如:

  • rate=1r/sburst=10,则每秒最多处理 1 个请求,额外 10 个请求会进入队列等待;
  • 队列按rate速率依次处理,若队列满(超过 10 个),新请求会被拒绝(返回 503)。

示例

1
2
# 速率1r/s,允许10个请求排队,排队请求不延迟
limit_req zone=mylimit burst=10 nodelay;

2. nodelaydelay:控制排队延迟

  • nodelay:队列中的请求不等待,立即处理(但总速率不超过rate)。适合允许突发流量但需控制并发的场景;
  • delay=N:队列中前N个请求立即处理,从第N+1个请求开始按rate延迟处理。用于精确控制并发数。

示例

1
2
# 前5个请求立即处理,第6个及以后按rate延迟处理
limit_req zone=mylimit burst=10 delay=5;

3. limit_req_log_levellimit_req_status

  • limit_req_log_level:指定限流时的日志级别(默认error),如notice
  • limit_req_status:指定被限流的请求返回的 HTTP 状态码(默认 503)。

示例

1
2
3
4
5
location /api {
limit_req zone=mylimit burst=10 nodelay;
limit_req_log_level notice; # 限流日志记为notice级别
limit_req_status 429; # 限流时返回429(Too Many Requests)
}

实战场景:不同维度的限流配置

1. 按 IP 限流(最常用)

限制单个 IP 的请求速率,防止单 IP 恶意攻击:

1
2
3
4
5
6
7
8
9
10
11
http {
# 按IP限流,每秒最多5个请求
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=5r/s;
}

server {
location /login {
limit_req zone=ip_limit burst=20 nodelay; # 允许20个突发请求
proxy_pass http://backend;
}
}

2. 按 URL 限流(保护特定接口)

限制对某一 URL 的总请求速率,避免热点接口被冲垮:

1
2
3
4
5
6
7
8
9
10
11
http {
# 按URL限流,每秒最多100个请求
limit_req_zone $request_uri zone=url_limit:20m rate=100r/s;
}

server {
location /api/payment { # 支付接口,需严格限流
limit_req zone=url_limit burst=50; # 允许50个突发请求
proxy_pass http://payment_service;
}
}

3. 结合if条件限流

仅对特定请求限流(如非内部 IP):

1
2
3
4
5
6
7
8
9
10
11
12
13
http {
limit_req_zone $binary_remote_addr zone=external_limit:10m rate=3r/s;
}

server {
location / {
# 若客户端IP不是内部网段,则应用限流
if ($remote_addr !~* ^192\.168\.) {
limit_req zone=external_limit burst=10 nodelay;
}
proxy_pass http://backend;
}
}

注意事项与优化

  1. 共享内存大小zone的大小需根据key的数量调整(如按 IP 限流,1M 约存 16000 个 IP,10M 可存 16 万个);

  2. 避免过度限流burstrate需根据业务峰值设置(如正常峰值 100r/s,可设rate=120r/sburst=50);

  3. 配合连接数限制:限流(limit_req)控制请求速率,limit_conn控制并发连接数,二者结合更安全:

1
2
3
# 限制单个IP最大并发连接数为10
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn conn_limit 10;
  1. 白名单配置:对内部 IP 或信任来源关闭限流,避免影响正常业务:
1
2
3
4
5
6
7
8
# 定义白名单变量
geo $limit {
default 1;
192.168.0.0/24 0; # 内部网段不限流
}

# 仅对白名单外的IP应用限流
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s if=$limit;

效果验证与日志分析

  • 验证方法:使用ab(Apache Bench)工具模拟并发请求:

    1
    ab -n 20 -c 5 http://example.com/api  # 发送20个请求,并发5个
  • 日志查看:Nginx 日志会记录被限流的请求(默认状态码 503),可通过日志分析限流效果:

    1
    192.168.1.100 - - [10/Jul/2025:10:00:00 +0800] "GET /api HTTP/1.1" 503 199 "-" "ApacheBench/2.3"

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10