limit_conn和limit_req是11个处理请求阶段中的preaccess阶段。
limit_conn 模块
用于限制每个客户端的并发连接数
生效范围:
全部worker进程(基于共享内容)
限制的有效性取决于key的设计,依赖于realip获取到的真实客户端ip
limit_conn_zone指令:用于定义共享内存和key关键字
上下文:http
limit_conn_zone key zone=name:size; # key一般是真实客户端ip,zone就是共享内存,那么是共享内存的名字,size大小
limit_conn指令:限制并发连接数
上下文:server,http,location
limit_conn zone_name number; #zone_name就是刚刚定义的共享内存的名字
limit_conn_log_level指令:发生限制并发时的日志级别,当限制了并发,就会记录到日志中,默认[error]级别。
上下文:server,http,location
limit_conn_log_level error|info|notice|warn;
limit_conn_status指令:限制发生时返回客户端的错误码
上下文:server,http,location
limit_conn_status code; # 默认503
小实验:
/var/www/html/index.html的内容写多一点,这样一个请求就会花较长的时间才能请求完,在这段时间内马上再开一个窗口再请求一次就可以模拟2个并发。
本地开2个cmd,都执行命令:
curl http://limit.zbpblog.com:8080
第一个显示index.html内容
第二个报500错误
试验成功。
limit_req模块
该模块用于限制同一个IP在特定时间内的请求数。作用范围也是所有worker进程,所以也需要分配共享内存。
使用算法leaky bucket。可以想象流量是一个水龙头,limit_req是一个桶,当有突发流量的时候,如果没有桶水龙头的水流的太快,服务器处理不过来;有桶的时候,水龙头的水流入桶中,桶的水再慢速的流出来,水龙头的水流入桶的速度比水流出桶的速度快,此时桶就会蓄水,这样bucket就限制了流速。如果桶满了,水龙头就关掉不再放水,也就是不再接受请求(返回一个503状态码)。等桶里面有空间了再继续放水。
使用这个算法,可以把突发流量变成每秒恒定的速度处理请求。可以在配置文件中定义这个“桶”有多大。
limit_req_zone key zone=name:size rate=rate; #定义共享内存,限速,rate单位r/s或r/m即限制每秒或每分钟处理的请求数
limit_req zone=name [burst=number] [nodelay] # 限制请求
其中burst就是桶的大小,即桶内可以存放多少个多出来的请求数
默认burst=0
nodelay 对burst中的请求不采取延时处理,而是立刻处理
limit_req_log_level # 同 limit_conn_log_level
limit_req_status # 同 limit_conn_status
问:如果同时设置了limit_conn和limit_req,即同时限制了限制并发数和限速,哪个先生效?
根据上面的流程图,limit_req在limit_conn之前。所以limit_req先生效,而且一旦触发限速,limit_conn就不会再检测,因为此时已经返回503
小实验:
在cmd中连续请求2次
curl http://limit.zbpblog.com:8080
发现第二次请求的时候就报503
使用 limit_req zone=req burst=3 nodelay; 再试一下,此时可以多请求个3,4次。
限速和限制并发数在 preaccess 阶段之前不生效
请区分 limit_conn 和 limit_req 的区别,一个是限制单ip用户的并发连接数,一个是限制单ip用户规定时间内的请求数。前者限制的是TCP连接数量,后者限制的是http请求数量。