nginx 的限流特技
nginx的限流是十分重要的一个技能,当大规模的流量洪峰到来,后端应用有可能被打垮。需要在Nginx这一层上作出限制。防止流量达到后端,雪上加霜。
nginx的限流模块是在 preaccess 阶段,这个阶段有两个模块,分别是 limit_req 和 limit_conn。一个是限制每秒请求数的,一个是限制每秒连接数的。
limit_conn 模块
这个模块会在全部的worker进程中生效(基于共享内存)。
限流是基于realip 模块提供的 $remote_addr 这个变量提供的真实的客户端ip地址。
为了限速首先需要定义一块共享内存(包括大小),以及key关键字。
# 定义共享内存,key 表示用什么来限速(一般是客户端ip)
Syntax: limit_conn_zone key zone=name size;
# 限制并发连接数
Syntax:limit_conn zone number;
# 限制发生时的日志级别
Syntax:limit_conn_log_level info|notice|warn|error
# 限制发生后的客户端返回错误码
Syntax:limit_conn_status code (默认是 503)
一个最简单的配置。
limit_conn_zone $binary_remote_addr zone=myaddr:10m;
server {
server_name limit.loki.wjx;
root html/;
location / {
limit_conn_status 500;
limit_conn_log_level warn;
limit_conn myaddr 1;
}
}
这个配置中的 $binary_remote_addr 是十进制的客户ip地址,zone共享内存起名叫做myaddr,开了10m。
这里针对客户端ip限制每个客户端的最大并发数是1 。
limit_req 模块
同样 limit_req 也是基于共享内存的,生效于全部的worker进程。
其用的是 leaky bucket 算法
限制突发流量
限制突发流量的方式就是用到了这个模块。假设有个峰值12Mbps。而平时流量只有2Mbps。用了 leaky bucket 算法可以把流量限制成恒定的3-4Mbps。
当 bursty 盆 满了之后,请求会被立刻返回错误。若没有满,则流量暂存盆中,响应会变慢。
#定义共享内存,key关键字以及限制速率
Syntax: limit_req_zone key zone=name:size rate=rate;
#限制并发连接数
Syntax:limit_req zone=name [burst=number] [nodelay];
burst 默认为0 。
nodelay会在瞬时提供处理(burst + rate)个请求的能力,请求超过(burst + rate)的时候就会直接返回503,永远不存在请求需要等待的情况。(这里的rate的单位是:r/s)
# 限制发生时的日志级别
Syntax:limit_req_log_level info|notice|warn|error
# 限制发生后的客户端返回错误码
Syntax:limit_req_status code (默认是 503)
一个简单的配置。
limit_req_zone $binary_remote_addr zone=one:10m rate=3r/m;
server {
server_name limit.loki.wjx;
root html/;
location / {
limit_req_status 500;
limit_req_log_level warn;
limit_req zone=one;
#limit_req zone=one burst=3;
#limit_req zone=one burst=3 nodelay;
}
}
这段配置写的是限制每分钟三个请求。
当启用 limit_req zone=one; 每秒3个。
当启动 limit_req zone=one burst=3; 每秒3个,桶里最大存3个。
当启用nodelay时,超出3个请求后直接返回失败,无视桶的存在。
接下来是实战中的例子
- 根据 ua 限速,防爬虫
##### limit req
map $http_user_agent $agent {
default "";
~*apachebench $http_user_agent;
~*spider $http_user_agent;
~*bot $http_user_agent;
~*slurp $http_user_agent;
~WinHttp\.WinHttpRequest $http_user_agent;
}
#limit_conn_zone $agent zone=ua_test:10m;
limit_req_zone $agent zone=req_ua:10m rate=1r/m;
- 根据ip进行限速
geo $whiteiplist {
default 1;
127.0.0.1 0;
10.0.0.0/8 0;
}
map $whiteiplist $limit {
1 $binary_remote_addr;
0 "";
}
limit_req_zone $limit zone=ac_limit:500m rate=8r/s;
限速
location / {
limit_req zone=req_ua burst=3 nodelay forbid_action=@excess;
limit_req zone=ac_limit burst=16 nodelay forbid_action=@excess;
proxy_pass http://xxxxx_backend;
}
location @excess {
set $xlocation 'excess';
return 204 "{\"status\":1}";
}
limit_rate 指令
limit_rate 不是一个limit_conn 和 limit_req 提供的限速指令,这是http_core_module 提供的。其功能也十分的简单。 限制每秒传输字节数。例如:
location /flv/ {
flv;
limit_rate_after 20m;
limit_rate 100k;
}
表示在下载前20m时不限速,后续限速100k/s。