Nginx http_limit_req模块详解

简介

在配置nginx的过程中我们需要考虑受到攻击或恶意请求的情况,比如单用户恶意发起大量请求,这时http_limit_req模块可以帮助我们对其进行限制。

ngx_http_limit_req_module模块用于限制请求的处理速率,特别是单一的IP地址的请求的处理速率。使用漏桶算法进行限制。

官方英文文档: http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

配置示例

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    limit_req_zone $binary_remote_addr$uri zone=two:10m rate=1r/s;
 
    ...
 
    server {
 
    ...
 
    location /search/ {
        limit_req zone=one burst=10 nodelay;
        limit_req zone=two burst=5 nodelay;
    }
    ...
}

此配置代表:

  • 对于同一ip不同请求地址,限制平均速率为5请求/秒,超过部分进行延迟处理,若超过10请求/秒,丢弃超过部分。
  • 对于同一ip相同请求地址,限制平均速率为1请求/秒,超过部分进行延迟处理,若超过5请求/秒,丢弃超过部分。

基本指令

limit_req_zone

语法:

limit_req_zone key zone=name:size rate=rate;

配置段:http

此指令用于声明请求限制zone,zone可以保存各种key的状态,name是zone的唯一标识,size代表zone的内存大小,rate指定速率限制。

参数详解:

1.key

若客户的请求匹配了key,则进入zone。可以是文本、变量,通常为Nginx变量。

如$binary_remote_addr(客户的ip),$uri(不带参数的请求地址),$request_uri(带参数的请求地址),$server_name(服务器名称)。

支持拼接组合使用,如$binary_remote_addr$uri。

2.zone

使用zone=test,指定此zone的名字为test。

3.size

在zone=name后面紧跟:size,指定此zone的内存大小。如zone=name:10m,代表name的共享内存大小为10m。通常情况下,1m可以保存16000个状态。

4.rate

使用rate=1r/s,限制平均1秒不超过1个请求。使用rate=1r/m,限制平均1分钟不超过1个请求。

例子:

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

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

同一ip不同请求地址,进入名为one的zone,限制速率为5请求/秒。

同一ip同一请求地址,进入名为two的zone,限制速率为1请求/秒。

limit_req

语法:

limit_req zone=name [burst=number] [nodelay];

配置段:http,server,location

此指令用于设置共享的内存zone和最大的突发请求大小。

若请求速率超过了limit_req_zone中指定的rate但小于limit_req中的burst,则进行延迟处理,若再超过burst,就可以通过设置nodelay对其进行丢弃处理。

参数详解:

1.zone

使用zone=name指定使用名为name的zone,这个zone之前使用limit_req_zone声明过。

2.burst(可选)

burst用于指定最大突发请求数。许多场景下,单一地限制rate并不能满足需求,设置burst,可以延迟处理超过rate限制的请求。

3.nodelay(可选)

如果设置了nodelay,在突发请求数大于burst时,会丢弃掉这部分请求。因为如果只是延迟处理,就像”漏斗“,一旦上面加得快(请求),下面漏的慢(处理速度),”漏斗”总会有溢出的时候。这时,丢弃掉溢出的部分就显得很有意义了。

例子

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

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

单客户分为三种情况

  • 请求速率 < rate(1r/s),正常处理
  • rate(1r/s) < 请求速率 < burst(5r/s),大于rate部分延迟
  • burst(5r/s)  < 请求速率,大于burst部分丢弃(返回503服务暂时不可用)

limit_req_status

语法:

limit_req_status 503;

配置段:http,server,location

设置要响应拒绝的请求而返回的状态代码(默认为503服务不可用)。

limit_req_log_level

语法

limit_req_log_level info | notice | warn | error;

配置段:http,server,location

设置当速率超过限制时记录日志的级别。

geo结合

上边的是对所有IP限速,如果想设置限速白名单可按照如下配置:

http {
    geo $whiteiplist {
        default      0;
        127.0.0.1    1;
        172.16.0.0  1;
    }
 
    map $whiteiplist $limit {
        0  $binary_remote_addr
        1   "";
    }

    limit_req_zone $limit zone=why_req:10m rate=5r/s;
}

说明:

  1. geo指令定义一个白名单$whiteiplist, 默认值为1, 所有都受限制。 如果客户端IP与白名单列出的IP相匹配,则$whiteiplist值为0也就是不受限制。
  2. map指令是将$whiteiplist值为1的,也就是受限制的IP,映射为客户端IP。将$whiteiplist值为0的,也就是白名单IP,映射为空的字符串。
  3. limit_conn_zone和limit_req_zone指令对于键为空值的将会被忽略,从而实现对于列出来的IP不做限制。