在 linux 中,nginx 实现请求限流与并发控制主要依赖 limit_req_zone 和 limit_conn_zone 两个指令。前者基于共享内存中的键(如客户端 ip)记录请求频率,配合 limit_req 使用;后者限制每个键的并发连接数,配合 limit_conn 使用。通过合理配置这两个模块,可以有效防止恶意刷接口或资源耗尽。

如何配置基于 IP 的请求频率限制
要限制特定 IP 的请求频率,需要在 http 块中定义一个共享内存区域,并在 location 或 server 块中启用该规则。核心参数包括 rate(速率)、burst(突发容量)和 nodelay(是否立即处理突发)。当请求超过设定速率时,超出部分会被丢弃并返回 503 错误。

http {
# 定义限流区域:key为$binary_remote_addr,大小10m,速率1r/s
limit_req_zone $binary_remote_addr zone=ip_limit:10m rate=1r/s;
server {
listen 80;
server_name example.com;
location /api/ {
# 启用限流,允许5个请求的突发,且立即处理
limit_req zone=ip_limit burst=5 nodelay;
# 自定义错误页
error_page 503 /custom_503.html;
proxy_pass http://backend;
}
}
}
上述配置中,zone=ip_limit 引用了之前定义的内存区域。rate=1r/s 表示每秒允许一个请求。burst=5 表示当瞬时流量超过 1r/s 时,最多允许 5 个请求排队等待处理,而不是直接拒绝。nodelay 选项意味着这 5 个突发请求会立即被处理,而不是按速率均匀分布。如果没有 nodelay,突发请求将被延迟处理以符合速率要求。如果请求数超过 burst 加上基础速率允许的数量,Nginx 将返回 503 Service Temporarily Unavailable。
如何限制单个 IP 的并发连接数
除了限制请求频率,还需要防止单个 IP 建立过多的并发连接导致服务器资源耗尽。这可以通过 limit_conn_zone 和 limit_conn 来实现。与限流不同,连接数限制关注的是同时存在的活跃连接数量,而非请求到达的时间间隔。

http {
# 定义连接限流区域:key为$binary_remote_addr,大小10m
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
listen 80;
server_name example.com;
location / {
# 限制每个IP最多10个并发连接
limit_conn conn_limit 10;
# 可选:限制整个服务器的总连接数
# limit_conn server_conn 1000;
proxy_pass http://backend;
}
}
}
在这个配置中,limit_conn_zone 创建了一个名为 conn_limit 的共享内存区域,用于存储每个 IP 的连接计数。limit_conn conn_limit 10 表示对于每个 $binary_remote_addr(即客户端 IP),最多允许 10 个并发连接。一旦某个 IP 的连接数达到 10,新的连接请求将被拒绝,同样返回 503 错误。这种机制对于保护后端服务免受大量长连接(如 WebSocket 或大文件下载)攻击非常有效。需要注意的是,limit_conn 统计的是当前处于处理状态或等待响应的连接,而不仅仅是已建立的 TCP 连接。
当请求同时触发限流和连接限制时会发生什么
当 Nginx 同时启用了 limit_req 和 limit_conn 时,两者是独立判断的。如果一个请求既超过了频率限制,又超过了并发连接限制,Nginx 会根据配置的顺序进行检查。通常,连接检查先于请求频率检查执行。如果任一条件不满足,请求都会被拒绝。在这种情况下,返回的错误代码取决于首先触发的限制。如果连接数已满,返回 503;如果频率超限,也返回 503。可以通过 limit_req_status 和 limit_conn_status 指令自定义这些错误代码,例如改为 429 Too Many Requests 以符合 RESTful API 规范。











