博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

nginx笔记(五)

Posted on 2020-05-08 11:04  龙翔天下  阅读(355)  评论(0编辑  收藏  举报

对HTTP资源访问限制

nginx限制范围,有可能是:

  • 对指定键值(比如每个IP)的连接数;
  • 对指定键值(比如每秒/分钟之间允许处理的请求数)的访问频率;
  • 连接的下载速率。

一、连接数的限制

1、用 limit_conn_zone 指令定义某个键,并且共享内存区域参数(工作进程会使用该区域作为共享该键值数)。第1参数是一表达式作为键,第二参数zone,用于指定zone名称和它的大小。

limit_conn_zone $binary_remote_addr zone=addr:10m;

 

2、用 limit_conn 指令 在 location{},server{},或 http{} 上下文中使用连接限制,该指令的第一参数为上方定义的共享内存区域的名称,第二参数定义该键的允许连接数。

location /download/ {
     limit_conn addr 1;
}

 

上例限制了每个IP地址的连接数,因为 $binary_remote_addr 变量作为键。

另一个常用的限制连接数是指定某个服务器 $server_name变量:

http {
    limit_conn_zone $server_name zone=servers:10m;

    server {
        limit_conn servers 1000;
    }
}

 

 

二、限制访问频率

访问频率限制常用于DDOS攻击防范,或防止上游服务器群组同一时间处理过多的访问。该方法基于 leaky bucket 算法:请求以各种速率到达存储桶,并以固定速率离开存储桶。

使用频率限制前,需配置 limit_req_zone指令,有以下参数:

key键:该参数用于区分各客户端,通常用变量表示;

共享内存区:其名称和大小用于存储这些key键;

频率:请求访问频率限制设定,单位为每秒请求(r/s) 或者每分钟请求(r/m)。

limit_req_zone指令定义在http{}层级:

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

 

通过以上配置,共享内存区域 one 拥有 10MB 大小。该区保存 $binary_remote_addr变量值 即客户端IP。

注意: $remote_addr 也是记录客户端IP地址,而$binary_remote_addr 保存客户端IP地址值的二进制位数,使用空间更小。

            共享区域的大小可通过以下计算得出:$binary_remote_addr 的 IPV4地址值为4字节,在64位系统占用128字节。因此,大约16,000个IP地址的状态信息占用该区域的1MB大小。

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

区域设置好后,就可以用 limit_req 指令在 server{}、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 错误。

 

三、测试请求频率限制

在配置真实环境下的频率限制前,可以用 dry run 模式不限制请求处理,但会将过多请求的问题记录下来。dry run模式开启使用 limit_req_dry_run 指令:

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

 

日志中记录 dry_run标记:

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"

 

 

四、处理过多请求的选项

由于流量趋向于突发性,因此在流量突发期间响应客户端请求返回错误不是最好的情况。

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个,则超出的请求放入one区。one区已满则过多的请求排入队列,队列大小5个。队列中的请求处理将请不超出设定的总速率。超出burst限制,将会返回503。

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

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

 

 

另外,delay参数可以定义了延迟过多请求以符合定义的速率限制的时间点:

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

 

使用此配置时,前3个请求(延迟)将无延迟地传递,接下来的2个请求(突发-延迟)将以总速率不大于指定速率的方式延迟,进一步的请求将被拒绝,因为总突发大小已超过,往后的请求将被延迟。

 

五、限制带宽

限制每条连接的带宽使用,使用 limit_rate 指令:

location /download/ {
    limit_rate 50k;
}

 

以上设置了访问 /download/的每个客户端在每个连接至多使用50K每秒的速率。不过,这里没有限制同一客户端同时开设多个连接。所以要做到下载速度不能超出指定值,那么同时也要限制连接数量:

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

    还可以限制客户端在下载一定数量的数据后才进行限制速度,请使用 limit_rate_after 指令。比如允许客户快速下载一定数量的数据(例如,文件标头-电影索引)后,开始限制下载其余数据的速率。

   以下示例合并使用了连接数和带宽限制。每个客户端地址允许的最大连接数设置为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;
    }
}

 

 

限制对代理TCP资源的访问

一、限制IP地址

allow和deny指令能分开对指定的IP地址或地址段允许或禁止访问。这两指令设置在stream或server上下文中。

如果设置了一系列规则,则么匹配按顺序从头到尾,直到头一条匹配到为止。

stream {
    #...
    server {
        listen 12345;
        deny   192.168.1.2;
        allow  192.168.1.1/24;
        allow  2001:0db8::/32;
        deny   all;
    }
}

 

上例中按顺序,192.168.1.1/24为允许访问,并排除192.168.1.2。而2001:0db8::/32的IPV6地址则被允许,并排除其他所有IP地址。

 

二、限制TCP连接数

nginx能限制单一IP同时建立的TCP连接数,这对防止DoS攻击很有效。

首先,在 stream 上下文使用 limit_conn_zone 指令定义存储连接到一服务器的最大TCP连接数区域,和与其相关的键。

stream {
    #...
    limit_conn_zone $binary_remote_addr zone=ip_addr:10m;
    #...
}

 

上例中,该键使用 $binary_remote_addr 变量定义。而共享存储区名为ip_addr,具有10MB大小。

区域定义好后,再使用 limit_conn 指令限制连接。该指令第一参数为 limit_conn_zone 定义的区域名称,第二参数指明允许的各IP地址最大连接数。该指令可在stream 或 server上下文中定义。

stream {
    #...
    limit_conn_zone $binary_remote_addr zone=ip_addr:10m;

    server {
        #...
        limit_conn ip_addr 1;
    }
}

 

当限制每个IP地址的连接数时,请注意网络地址转换(NAT)设备后面的多个主机共享相同的IP地址。

 

三、限制带宽

要设置下载、上传的TCP连接速度,可以用 proxy_download_rate 或 proxy_upload_rate 指令:

server {
    #...
    proxy_download_rate 100k;
    proxy_upload_rate   50k;
}

 

上例设置了单个TCP连接拥有100K下载速率,和50K上传速率。

如果需要限制每个客户端的速率,可以限制连接数为1:

stream {
    #...
    limit_conn_zone $binary_remote_addr zone=ip_addr:10m;

    server {
        #...
        limit_conn ip_addr  1;
        proxy_download_rate 100k;
        proxy_upload_rate   50k;
    }
}