nginx安全:用limit_req_zone/limit_req限制连接速率(流量控制/限流)

一,limit_req的用途:

1,官方文档地址:

http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

 

2,用途:

限制用户在给定时间内HTTP请求的数量,

流量限制主要用作安全目的,

可以防止大量请求的攻击下服务被压垮,

可以减慢暴力密码破解的速率

 

3,原理:漏桶算法

在limit_req的限制下,请求被nginx以固定的速率处理,这个符合漏桶算法,

即流出的速率恒定。

 

说明:刘宏缔的架构森林是一个专注架构的博客,

网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/22/nginxlimitreqzonelimitreq-xian-zhi-lian-jie-su-lyu-liu/

         对应的源码可以访问这里获取: https://github.com/liuhongdi/

说明:作者:刘宏缔 邮箱: 371125307@qq.com

 

二,limit_req的配置举例:

1,常用的两个指令:

nginx.conf中

limit_req_zone:定义到http区域:

 limit_req_zone $binary_remote_addr zone=perip:20m rate=1r/s;

 

limit_req:定义到server或location区域

limit_req zone=perip;

 

说明:

变量:$binary_remote_addr,这里是客户端的ip地址,

          在这里是做限制的标识,是基于ip地址来限制

zone=perip:20m:  perip是内存区域的名字,

                         20m: 生成的内存区域的大小

rate=1r/s:       允放相同标识的客户端的访问频次,

在这个例子中:就是同一个ip地址在每秒内只能访问1次

 

2,例子一:以每秒处理1个请求的速率做限制

limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
... limit_req zone
=perip;

重启 nginx后测试:

[liuhongdi@centos8 logs]$ ab -c 10 -n 10 http://www.lhdtest.com/index.html
...
Concurrency Level:      10
Time taken for tests:   0.002 seconds
Complete requests:      10
Failed requests:        9
   (Connect: 0, Receive: 0, Length: 9, Exceptions: 0)
Non-2xx responses:      9
...

只有一个成功,有9个请求失败

时长是0.002 seconds

 

3,例子2:burst

增加burst,再次测试

limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
...
limit_req zone=perip burst=2;

说明:burst=2 允许2个突发,

          有大量请求时,超过频次限制的请求,会允许2个访问,

          注意:burst指定的请求数量,不会马上进行处理,

                    而是按照rate指定的值,以固定的速率进行处理。

          以10个并发请求为例:

          rate= 1r/s

          就是先处理1个,剩下的9个中,

           7个请求,直接返回503

           剩下的2个放到突发的队列中延迟执行,

          仍然按rate= 1r/s进行处理,所以需要约两秒的等待时间

[liuhongdi@centos8 logs]$ ab -c 10 -n 10 http://www.lhdtest.com/index.html
...
Concurrency Level:      10
Time taken for tests:   2.004 seconds
Complete requests:      10
Failed requests:        7
   (Connect: 0, Receive: 0, Length: 7, Exceptions: 0)
Non-2xx responses:      7
...

有7个请求失败

注意时间变成了2.004 seconds

 

4,例子三:nodelay

limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;
...
limit_req zone=perip burst=2 nodelay;

说明:

nodelay参数:

burst的队列虽然可以处理用户的需求,但需要用户按照处理时间等待,对用户不够友好,

nodelay参数允许请求在排队的时候就立即被处理,

这里有一点要注意:因为nodelay允许立即处理,也就是有并发请求时

事实上已经超过了rate设置的处理速率了,

所以要根据自己机器的实际情况设置这个值

 

理解nodelay:

nodelay只是对放到burst队列中的请求立即处理,

但处理完成后队列并不立即清空,

队列清空的速度仍然按原来的速度每秒一个清空,

所以当再有请求过来时,并不会马上又有两个burst请求被处理.

 

再次测试

[liuhongdi@centos8 logs]$ ab -c 10 -n 10 http://www.lhdtest.com/index.html
...
Concurrency Level:      10
Time taken for tests:   0.002 seconds
Complete requests:      10
Failed requests:        7
   (Connect: 0, Receive: 0, Length: 7, Exceptions: 0)
Non-2xx responses:      7
...

有7个请求失败

注意时间:这次是0.002 seconds

 

三,rate和burst应该设置为多少?

1,网站需要把动态生成的内容(java,php,python等程序生成)和静态内容分离到不同的虚拟主机

     因为静态内容不需要大量的计算,

     通常limit_req用于限制动态内容的访问频率

     

2,限流的目的不是让用户不能访问,

      而是为了保证用户能流畅的访问,

      所以需要根据页面的实际情况来限制

      如果一个页面打开时同时发出的请求比较多,

     (静态文件分离后要检查ajax请求数,

      可以根据生产环境的日志进行检查)

     则rate值不能低于并发的请求数.

     如果低于并发的情求数,会导致用户不能正常访问页面

 

3,我们在生产环境中的例子,仅供参考

     limit_req_zone $binary_remote_addr zone=reqperip:20m rate=20r/s;
     limit_req zone=reqperip burst=10 nodelay;

 

四,其他可配置的参数:

1,limit_req_status用来指定请求时报错产生的状态码:

limit_req_status 这个值默认是503,

可以指定为一个自定义的值,

例如:444

说明:444是nginx自定义的一个非标准状态码,

       它会立即关闭连接,连响应头也不给客户端发

         可以在受到恶意攻击时使用这个状态码

 

2,limit_req_log_level   当报错时记录到日志的错误级别,

默认值是error

可选值: info | notice | warn | error

不建议改动这个值

 

五,查看nginx的版本:

[root@centos8 conf.d]# /usr/local/soft/nginx-1.18.0/sbin/nginx -v
nginx version: nginx/1.18.0

 

posted @ 2020-05-09 12:56  刘宏缔的架构森林  阅读(8032)  评论(0编辑  收藏  举报