Home > 工作记录 > 正文

【工作】Nginx限制IP并发连接数和请求数的研究

写在前面:

公司最近需要对某个虚拟主机进行用户并发链接限制,具体需求是当某个IP超过指定的链接数时,返回服务繁忙的提醒页面。

实现过程:

Nginx限制IP连接数使用的是ngx_http_limit_conn_module模块,可以通过这个模块的中“limit_conn_zone”和“limit_conn”两个参数实现。
 
Nginx限制请求数使用的是ngx_http_limit_req_module模块,可以通过这个模块中“limit_req_zone”和“limit_req”两个参数实现。

ngx_http_limit_conn_module模块研究:

limit_conn_zone:

功能:用于定义一个zone,该zome将会被用于存储会话状态。能够存储的会话数量是由定义的size大小和系统参数memory_max_size的大小决定的。
语法:limit_conn_zone key zone=name:size;
默认值: none
配置段: http
实例:
      limit_conn_zone $binary_remote_addr zone=conn_ip:10m;
      limit_conn_zone $server_name zone=conn_server:10m;
 
key参数对应实例:
    $binary_remote_addr     
    #二进制的IP地址,就是客户端的来源IP
    
    $server_name            
    #虚拟主机名,如本文将会用到的www.ceshi.com
 
name参数对应实例:
    zone=conn_ip 
    zone=conn_server      
    #zone是共享内存空间,作用是保存每个key对应的连接数,此处可以按照需求自己定义名字。
    
size参数对应实例:
    10m 
    #共享内存空间大小,一个二进制的ip地址在32位机器上占用32个字节,在64位机器上占用63个字节,10M等于的字节数为:10x1024x1024/32 = 327680,也就是32位机器可以存放326780个ip地址,64位可以存放163840个ip地址。如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误

limit_conn:

功能:用于为一个会话设定最大的并发连接数。如果并发请求数超过这个限制,会返回的响应状态码(默认是503)

语法: limit_conn zone number;
默认值:none
配置段:http, server, location 
实例:
       limit_conn conn_ip 10;                #限制某个IP来源的连接并发数,此处为10个
       limit_conn conn_server 1000;    #限制某个虚拟服务器的总连接数,此处为1000个
 
“conn_ip” 和 “conn_server”就是上面定义的zone的名字,所以定义时候需要唯一可识别含义。

limit_conn_log_level:

功能:当达到最大限制连接数后,记录日志的等级。
语法:limit_conn_log_level info | notice | warn | error
默认值:error
配置段:http, server, location

limit_conn_status:

功能:该参数在1.3.15版本引入的。指定当超过限制时,返回的状态码(默认是503),code值只能设置在400到599之间。
语法: limit_conn_status code;
默认值: limit_conn_status 503;
配置段: http, server, location

limit_rate:

功能:对每个连接的速率限制。参数rate的单位是字节/秒,设置为0将关闭限速。 按连接限速而不是按IP限制,因此如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的2倍。
语法:limit_rate rate
默认值:0
配置段:http, server, location, if in location

配置实例:

下面是一个配置的实例模板,只贴出主要的参数,其他参数可以根据自己的需要自行添加:
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile           on;
    keepalive_timeout  65;
    
    limit_conn_zone $binary_remote_addr zone=conn_ip:10m;
    limit_conn_zone $server_name zone=conn_server:10m;
    limit_conn_log_level info; 

    server {
    listen       80;
    server_name  www.ceshi.com;
    index  index.html index.htm login.html;

    access_log logs/www.ceshi.com_access.log;
    error_log  logs/www.ceshi.com_error.log;

    location / {
       root /opt/web/;
       limit_conn conn_ip 10;
       limit_conn conn_server 1000;
    }

    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
          root   /opt/web/error_page/;
      }
 }
}
 
上面的配置实现的效果是:
1.当某个IP访问www.ceshi.com这个域名时,如果这个IP得并发连接超过10,则会报503(Service Temporarily Unavailable),表示服务暂时不可用,此时会返回给用户我们事先定义好错误页面。由“limit_conn conn_ip 10;”实现。
2.当访问www.ceshi.com这个域名的链接总数超过1000时,同样会报503,返回定义好的错误页面。由“limit_conn conn_server 1000;”实现
3.“error_page”定义返回的错误页面,需在定义的/opt/web/error_page/目录下创建50x.html文件,里面内容根据需要定义。

测试验证:

为了测试上面的配置是否有效果,可以使用apache的压力测试工具ab。
 
找一台测试机安装ab软件:
# yum install httpd-tools -y
 
添加域名和Web Server的域名解析:
# 172.16.20.227  www.ceshi.com
 
关于ab的具体使用方法请自行Google,下面先测试当IP并发数超过10个时候,Nginx是否可以拦截请求返回错误页面,由于无法模仿正常访问返回页面内容,此处我们以查看Nginx的访问日志判断。
 
# ab -n 10 -c 10  http://www.ceshi.com/
 
-n代表请求数,-c代表并发数
 
先发送10个并发,同时再开一个终端监控错误访问日志观察。
# tail -f /opt/nginx-1.9.3/logs/www.ceshi.com_error.log
 
下图可以看出,当并发数为10的时候,无论执行多少次,都没有错误,所有请求都成功:
20170110180148
 
备注:
 
Complete requests:      10   #总请求数
Failed requests:        0    #失败请求 
 
现在我们把并发数调整到11,同时还打开日志,观察现象:
# ab -n 11 -c 11  http://www.ceshi.com/
20170110180310
 
可以看到有一个错误请求,然后再查看服务器上的错误日志信息如下:
[[email protected] ~]# tail -f /opt/nginx-1.9.3/logs/www.ceshi.com_error.log 
2017/01/10 17:30:17 [error] 4492#0: *116312 limiting connections by zone "conn_ip",client: 172.16.20.226, server: www.ceshi.com, 
request: "GET / HTTP/1.0", host: "www.ceshi.com"
由上面报错可以看出,有一个IP为172.16.20.226访问被限制连接了,然后查看访问日志信息:
0170110180445
 
有一个访问报503错误了,这个访问如果用浏览器查看的话就会跳到我们定义的错误页面50x.html上。
 
至此关于公司得基本需求就可以实现了,接下来研究另外一个配置limit_conn conn_server 1000;
 
由于我们设置的IP连接数限制远小于虚拟主机总的链接数,所以对配置文件稍作修改,将conn_ip参数调大,如下:
 
limit_conn conn_ip 1000;
limit_conn conn_server 100;
 
# /opt/nginx-1.9.3/sbin/nginx -s reload
 
接下来继续使用ab测试(记得先清空之前的访问日志):
# ab -n 100 -c 100  http://www.ceshi.com/
 
20170110180542
 
可以看到当请求并发总数为100时候,没有报错请求,Nginx也没错误,接下来调大并发数:
# ab -n 110 -c 110  http://www.ceshi.com/
 
20170110180622
 
20170110180919
 
上面可以看出有10个错误请求,被"conn_server"这个zone限制了,同时访问日志里面也有503报错,此处就不再展示.
 
以上就是关于Nginx限制用户并发连接数的简单研究,下面开始研究Nginx的请求数。
 

ngx_http_limit_req_module模块指令研究:

limit_req_zone:

功能:利用令牌桶原理,来限制用户的连接频率,通过设置一块共享内存限制域用来保存键值的状态参数。 特别是保存了当前超出请求的数量。 键的值就是指定的变量(空值不会被计算)

语法: limit_req_zone $variable zone=name:size rate=rate;
默认值: none
配置段: http

实例:limit_req_zone $binary_remote_addr zone=req_ip:10m rate=1r/s;

以上参数对应实例的含义和“limit_conn_zone”是一样的,此处不再介绍,重点说一下”rate“这个参数。

rate参数对应实例:

     rate=1r/s;

     #指每个IP平均处理的请求频率为每秒一次,此值可以设置成每秒处理请求数或者每分钟处理请求数,但必须是整数,所以如果你需要指定每秒处理少于1个的请求,2秒处理一个请求,可以使用 “30r/m”。

limit_req:

功能:设置对应的共享内存限制域和允许被处理的最大请求数阈值。 如果请求的频率超过了限制域配置的值,请求处理会被延迟,所以所有的请求都是以定义的频率被处理的。 超过频率限制的请求会被延迟,直到被延迟的请求数超过了定义的阈值,这时,这个请求会被终止,并返回503 (Service Temporarily Unavailable) 错误。这个阈值的默认值为0

语法: limit_req zone=name [burst=number] [nodelay];
默认值: —
配置段: http, server, location

实例:limit_req zone=req_ip burst=5;

burst参数对应实例含义:

     burst=5

    #这个配置的意思是设置一个大小为5的缓冲区,当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内,如果此还存区也满了则会返回503

     nodelay
    如果设置此参数,超过访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所有请求会等待排队

limit_req_log_level:

功能:设置你所希望的日志级别,当服务器因为频率过高拒绝或者延迟处理请求时可以记下相应级别的日志。 延迟记录的日志级别比拒绝的低一个级别;比如, 如果设置“limit_req_log_level notice”, 延迟的日志就是info级别。

语法: limit_req_log_level info | notice | warn | error;
默认值: limit_req_log_level error;
配置段: http, server, location

limit_req_status:

功能:该参数在1.3.15版本引入的。指定当超过限制时,回的状态码(默认是503),code值只能设置在400到599之间。
语法: limit_req_status code;
默认值: limit_req_status 503;
配置段: http, server, location

配置实例:

以下是结合上面的ngx_http_limit_conn_module模块的一个实例,具体值根据自己需要修改。

http {
    limit_conn_zone $binary_remote_addr zone=conn_ip:10m;
    limit_conn_zone $server_name zone=conn_server:10m;
    limit_req_zone  $binary_remote_addr zone=req_ip:10m rate=10r/s;
    server {       
        location / {
            limit_conn conn_ip 10;          
            limit_conn conn_server 1000;   
            limit_req zone=req_ip burst=5; 
        }
        
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }  
    }
}

测试验证:

1.我先以一个并发分别请求100次,1000次,10000次测试服务器反应,如下图:

20170111161613

Failed requests:        0    #失败请求 

Requests per second:    10.10 [#/sec] (mean) #平均每秒请求数

由以上两个参数可以看出,当并发数为1时候,无论请求多少次,请求都会被处理,且查看日志发现没有报错,全部为200,只是被延迟处理了,而请求数都被限制在了每秒10个,这个说明“rate=10r/s”参数生效了。

2.接下来我以10个并发发送10个请求数,如下图:

20170111162326

由上图可以看出,有5个请求报错了,而每秒平均请求数为24.75个,显然超过了配置中的限制,此时访问日志也出现了503的报错,错误日志中报错信息如下:

20170111162651

可以看出有5个请求被”req_ip“这个zone拦截了!

关于Nginx限制IP并发连接数和请求数的研究先到此,更深入研究会随着线上项目需求推进!

参考文章:http://www.ttlsa.com/

上一篇:【理论】Nginx连接数、请求数限制应用详解
下一篇:【理论】HTTP状态码大全
【分享】NGINX访问https跳转到http的解决方法

【分享】NGINX访问https跳转到http的解决方法

【工作】Linux使用非root用户启动Apache、Nginx等服务的方法

【工作】Linux使用非root用户启动Apache、Nginx等服务的方法

【工作】Nginx使用stream模块实现TCP负载均衡(TCP协议转发、Socket转发)

【工作】Nginx使用stream模块实现TCP负载均衡(TCP协议转发、Socket转发)

【理论】Nginx的内置变量和作用

【理论】Nginx的内置变量和作用

【理论】Nginx “upstream”模块详解和各负载均衡模式对比测试

【理论】Nginx “upstream”模块详解和各负载均衡模式对比测试

【工作】解决Nginx访问日志中报favicon.ico文件404错误

【工作】解决Nginx访问日志中报favicon.ico文件404错误

【理论】HTTP状态码大全

【理论】HTTP状态码大全

发表评论

昵称 *
邮箱 *
网址

沙发空闲中,快来抢!