高并发场景下接口防刷!3 分钟配置 Nginx 基于 IP 限流实战指南


我们系统上线后可能会遭遇外部刷接口、暴力测试等行为,尤其是权益类的服务,羊毛党的黄牛特别多。我之前有做过权益兑换系统,这个服务经常会被暴力刷接口,我们可以通过
Nginx 限流机制,熔断刷子流量,从而提升服务可用性。

在 Nginx 中,可以使用 ** 限流 ** (Rate Limiting)功能来控制进入服务器的请求数量。Nginx 提供了两个主要的限流模块:

  1. limit_req 模块:限制请求的速率(单位时间内请求的次数)。
  2. limit_conn 模块:限制并发连接数(每个 IP 地址允许的最大并发连接数)。

这两个模块可以组合使用,用于不同的限流需求,比如限制单位时间内的请求数或并发连接数。

limit_req 模块:限制请求速率

limit_req 模块可以限制特定 IP 地址的请求频率。例如,限制每秒钟一个 IP 地址只能发出一定数量的请求。

配置示例:

http {  
    # 定义一个限流区域  
    limit_req_zone$binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;  
  
    server {  
        listen80;  
        server_name example.com;  
  
        location / {  
            # 使用上面定义的限流区域,限制请求频率  
            limit_req zone=req_limit_per_ip burst=20 nodelay;  
  
            # 处理正常请求  
            root /usr/share/nginx/html;  
            index index.html;  
        }  
    }  
}  

解释:

  • limit_req_zone 定义一个名为 req_limit_per_ip 的限流区域。 $binary_remote_addr 是客户端的 IP 地址,以二进制格式存储,可以减少内存消耗。 rate=10r/s 限制每秒最多 10 次请求。 zone=req_limit_per_ip:10m 表示存储在内存中,并且该区域的大小是 10MB,可以存储多个 IP 地址的限流信息。
  • limit_req 在具体的 location 配置中启用限流,使用定义好的 req_limit_per_ip 区域。 burst=20 允许一定的请求突发,即在瞬间请求量超过正常限速时,最多可以允许 20 个请求超出限速。 nodelay 表示一旦超出请求限制,就立即拒绝请求,而不是延迟处理。

limit_conn 模块:限制连接数

limit_conn 模块限制每个客户端(每个客户端都有 IP 地址)的并发连接数。这对于防止单个客户端占用过多服务器资源非常有效。

配置示例:

http {  
    # 定义每个客户端(IP 地址)的最大连接数为 1  
    limit_conn_zone$binary_remote_addr zone=conn_limit_per_ip:10m;  
  
    server {  
        listen80;  
        server_name example.com;  
  
        location / {  
            # 限制每个 IP 的最大连接数  
            limit_conn conn_limit_per_ip 1;  
  
            # 处理正常请求  
            root /usr/share/nginx/html;  
            index index.html;  
        }  
    }  
}  

解释:

  • limit_conn_zone 定义了一个名为 conn_limit_per_ip 的区域,用于存储每个 IP 地址的连接信息, zone=conn_limit_per_ip:10m 指定了 10MB 的存储空间。
  • limit_conn location 配置中启用连接限制,限制每个 IP 地址只能有一个并发连接。

组合使用 limit_req 和 limit_conn

我们可以同时使用 limit_req limit_conn 来限制请求速率和并发连接数,从而实现更严格的流量控制。

配置示例:

http {  
    # 定义请求频率限制区域  
    limit_req_zone$binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;  
  
    # 定义并发连接数限制区域  
    limit_conn_zone$binary_remote_addr zone=conn_limit_per_ip:10m;  
  
    server {  
        listen80;  
        server_name example.com;  
  
        location / {  
            # 限制请求速率,每秒最多 5 次请求  
            limit_req zone=req_limit_per_ip burst=10 nodelay;  
  
            # 限制并发连接数,每个 IP 最多允许 1 个连接  
            limit_conn conn_limit_per_ip 1;  
  
            # 处理正常请求  
            root /usr/share/nginx/html;  
            index index.html;  
        }  
    }  
}  

解释:

  • limit_req_zone 限制每个 IP 地址的请求频率,每秒最多 5 次请求。 burst=10 允许 10 次请求的突发。
  • limit_conn_zone 限制每个 IP 地址的最大并发连接数为 1。

** 其他常见配置选项 **

  • burst 表示允许的请求突发数量。例如, burst=10 允许在短时间内超过规定的请求速率(如每秒 10 次请求),但是请求数不会超过突发限制。
  • nodelay 表示一旦请求超过了速率限制,则立即返回 503 错误,而不是延迟处理。

** 限流时返回的状态码 **

当请求超过了限流限制, Nginx 会返回 ** 503 Service Unavailable ** 错误。我们可以通过以下配置定制返回的错误页面:

http {  
    limit_req_zone$binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;  
  
    server {  
        listen80;  
        server_name example.com;  
  
        location / {  
            limit_req zone=req_limit_per_ip burst=10 nodelay;  
  
            # 设置请求超限时返回的页面  
            error_page503 /custom_503.html;  
            root /usr/share/nginx/html;  
            index index.html;  
        }  
    }  
}  

在这个配置中,当请求超过限制时,Nginx 会返回自定义的 503 页面 /custom_503.html

如何查看访问日志中的 503 错误

通过以下命令行查看:搜索日志中 503 字符

grep " 503 " /var/log/nginx/access.log