NGINX 限流配置

NGINX限流配置

摘自:https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http/

介绍

使用 NGINX 和 NGINX Plus,可以限制:

  • 每个键值的连接数(例如,每个 IP 地址)
  • 每个键值的请求率(一秒或一分钟内允许处理的请求数)
  • 连接的下载速度

请注意,IP 地址可以在 NAT 设备后面共享,因此应明智地使用 IP 地址限制。

 

限制连接数

限制连接数:

  1. 使用limit_conn_zone指令来定义键并设置共享内存区域的参数(工作进程将使用该区域来共享键值的计数器)。作为第一个参数,指定计算为键的表达式。在第二个参数zone中,指定区域的名称及其大小:

    limit_conn_zone $binary_remote_addr zone=addr:10m;
    
  2. 使用limit_conn指令在 、 或 上下文中location {}应用server {}限制http {}第一个参数指定共享内存区域的名称,第二个参数指定每个键允许的连接数:

    location /download/ {
         limit_conn addr 1;
    }
    

    由于该$binary_remote_addr变量被用作键,因此连接数受限于 IP 地址。

    限制给定服务器的连接数的另一种方法是使用$server_name变量:

    http {
        limit_conn_zone $server_name zone=servers:10m;
    
        server {
            limit_conn servers 1000;
        }
    }
    

 

限制请求率

限速可用于防止 DDoS 攻击,或防止上游服务器同时被太多请求淹没。该方法基于以下leaky bucket算法:请求以各种速率到达存储桶并以固定速率离开存储桶。

在使用限速之前,您需要配置“漏桶”的全局参数:

  • key - 用于区分一个客户端和另一个客户端的参数,通常是一个变量
  • 共享内存区域 - 保存这些键状态的区域的名称和大小(“漏桶”)
  • r/srate - 每秒请求数 ( ) 或每分钟请求数( )中指定的请求速率限制r/m(“漏桶耗尽”)。每分钟请求数用于指定小于每秒一个请求的速率。

这些参数是使用limit_req_zone指令设置的。该指令在http {}级别上定义 - 这种方法允许将不同的区域和请求溢出参数应用于不同的上下文:

http {
    #...
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
}

使用此配置,将one创建大小为 10 兆字节的共享内存区域。该区域保持使用该$binary_remote_addr变量设置的客户端 IP 地址的状态。请注意,与它相比$remote_addr,它还保存客户端的 IP 地址,$binary_remote_addr保存 IP 地址的二进制表示,它更短。

共享内存区域的最佳大小可以使用以下数据来计算:$binary_remote_addr对于 IPv4 地址,value 的大小为 4 字节,存储状态在 64 位平台上占用 128 字节。因此,大约 16,000 个 IP 地址的状态信息占用了 1 兆字节的区域。

如果 NGINX 需要添加新条目时存储空间耗尽,它会删除最旧的条目。如果释放的空间仍然不足以容纳新记录,NGINX 返回状态码503 Service Unavailable可以使用limit_req_status指令重新定义状态代码。

设置区域后,您可以在 NGINX 配置中的任何位置使用请求限制,并为 a 或context 指定limit_reqserver {}location {}http {}

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one;
        }
    }
}

使用此配置,NGINX 将在该位置1内每秒处理不超过请求。/search/这些请求的处理以这样一种方式延迟,即总速率不大于指定的速率。如果请求数量超过指定速率,NGINX 将延迟处理此类请求,直到“桶”(共享内存区域one)已满。对于到达完整存储桶的请求,NGINX 将响应503 Service Unavailable错误(如果未使用limit_req_status重新定义)。

 

测试请求速率限制

在配置实际限速之前,可以尝试不限制请求处理速率的“dry run”模式。但是,此类过多的请求仍会记入共享内存区域并记录下来。可以使用limit_req_dry_run指令启用“试运行”模式:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one;
            limit_req_dry_run on;
        }
    }
}

每个超出定义速率限制的请求都将被记录为“试运行”标记:

2019/09/03 10:28:45 [error] 142#142: *13246 limiting requests, dry run, excess: 1.000 by zone "one", client: 172.19.0.1, server: www.example.com, request: "GET / HTTP/1.0", host: "www.example.com:80"

 

处理过多的请求

请求被限制为符合limit_req_zone指令中定义的速率。如果请求的数量超过指定的速率并且共享内存区域已满,NGINX 将响应错误。由于流量往往是突发的,因此在流量突发期间返回错误以响应客户端请求并不是最好的情况。

NGINX 中这种过多的请求可以被缓冲和处理。limit_req指令的burst参数设置等待以指定速率处理的过多请求的最大数量:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one burst=5;
        }
    }
}

使用此配置,如果请求速率超过1每秒请求,则超出该速率的请求将被放入 zone one当 zone 已满时,过多的请求会被排队(burst),这个队列的大小是5requests。队列中的请求处理以这样的方式延迟,即总速率不大于指定的速率。超出突发限制的请求将被拒绝并出现503错误。

如果在流量突发期间不希望请求延迟,请添加nodelay参数:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one burst=5 nodelay;
        }
    }
}

burst使用此配置,无论指定如何,都会立即处理限制内的过多请求rate,超过突发限制的请求将被拒绝并出现503错误。

 

延迟过多的请求

处理过多请求的另一种方法是立即处理一些此类请求,然后应用速率限制,直到拒绝过多请求为止。

这可以通过delayburst参数来实现。delay参数定义了延迟过多请求以符合定义的速率限制的点:

http {
    #...

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        #...

        location /search/ {
            limit_req zone=one burst=5 delay=3;
        }
    }
}

使用此配置,前 3 个请求 ( delay) 会立即通过,接下来的 2 个请求 ( burstdelay) 会延迟,以使总速率不大于指定的速率,因为超过了总突发大小,将拒绝更多的请求,后续请求将被延迟。

 

同步多个共享内存区域的内容

如果您有一个具有多个 NGINX 实例的计算机集群并且这些实例使用该limit_req方法,则可以在以下条件下同步其共享内存区域的内容:

http {
    #...
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s sync;
}

有关详细信息,请参阅集群中的运行时状态共享

 

限制带宽

要限制每个连接的带宽,请使用limit_rate指令:

location /download/ {
    limit_rate 50k;
}

使用此设置,客户端将能够通过单个连接以50每秒千字节的最大速度下载内容。但是,客户端可以打开多个连接。因此,如果目标是防止下载速度大于指定值,则还应限制连接数。例如,每个 IP 地址一个连接(如果使用上面指定的共享内存区域):

location /download/ {
    limit_conn addr 1;
    limit_rate 50k;
}

要仅在客户端下载一定数量的数据后施加限制,请使用limit_rate_after指令。允许客户端快速下载一定量的数据(例如,文件头——电影索引)并限制下载其余数据的速率(让用户观看电影,而不是下载)可能是合理的。

limit_rate_after 500k;
limit_rate       20k;

以下示例显示了用于限制连接数和带宽的组合配置。允许的最大连接数设置为5 每个客户端地址的连接数,这适合大多数常见情况,因为现代浏览器通常一次最多打开 3 个连接。同时,提供下载的位置只允许一个连接:

http {
    limit_conn_zone $binary_remote_address zone=addr:10m

    server {
        root /www/data;
        limit_conn addr 5;

        location / {
        }

        location /download/ {
            limit_conn       addr 1;
            limit_rate_after 1m;
            limit_rate       50k;
        }
    }
}

 

动态带宽控制

limit_rate也可以指定为变量 - 这可以启用动态带宽用例,例如,允许对现代浏览器进行更高的带宽限制:

map $ssl_protocol $response_rate {
    "TLSv1.1" 10k;
    "TLSv1.2" 100k;
    "TLSv1.3" 1000k;
}

server {
    listen 443 ssl;
    ssl_protocols       TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;

    location / {
        limit_rate       $response_rate; # Limit bandwidth based on TLS version
        limit_rate_after 512;      # Apply limit after headers have been sent
        proxy_pass       http://my_backend;
    }
}
posted @ 2022-05-18 17:54  AmbitiousMice  阅读(905)  评论(0编辑  收藏  举报