流量限制(rate-limiting)。可以用来限制用户在给定时间内HTTP请求的数量。
流量限制可以用作安全目的。
通过将传入请求的速率限制为真实用户的典型值,并标识目标URL地址(通过日志),还可以用来抵御DDOS攻击。
该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。
流量限制使用漏桶算法(leaky bucket algorithm),该算法在通讯和分组交换计算机网络中广泛使用,用以处理带宽有限时的突发情况。
同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
}
}
limit_req_zone指令定义了流量限制相关的参数,而limit_req指令在出现的上下文中启用流量限制
limit_req_zone指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:
Key :定义应用限制的请求特性。
Zone :定义用于存储每个IP地址状态以及被限制请求URL访问频率的共享内存区域。
Rate :定义最大请求速率。
limit_req_zone指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加
limit_req指令,将流量限制应用在特定的location
或者server
块。
流量限制配置两个主要的指令,limit_req_zone和limit_req
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
#$binary_remote_addr 记录二进制的ip
#zone=mylimit:10m 限制规则的名字:从内存中拿取10m 名字在limit_req中直接调用
#rate=10r/s 每秒最多处理十个请求
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
limit_req zone=mylimit;
}
}
处理请求速率限制在每秒10个请求,超量的请求放入等待队列,等处理有空余位置,从队列中拿取请求
在limit_req中使用burst参数
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
#$binary_remote_addr 记录二进制的ip
#zone=mylimit:10m 限制规则的名字:从内存中拿取10m 名字在limit_req中直接调用
#rate=10r/s 每秒最多处理十个请求
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
limit_req zone=mylimit burst=20;
}
}
使用nodelay参数,将第一批超量的请求添加到缓冲队列,并对第一批缓冲队列请求进行访问,后续再来的请求继续进入缓冲队列进行排队,等待空余请求位置
在burst参数后添加nodelay参数
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
#$binary_remote_addr 记录二进制的ip
#zone=mylimit:10m 限制规则的名字:从内存中拿取10m 名字在limit_req中直接调用
#rate=10r/s 每秒最多处理十个请求
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
limit_req zone=mylimit burst=20 nodelay;
}
}
注意: 对于大部分部署,使用burst
和nodelay
参数来配置limit_req
指令。
geo $lim{
default 1; //默认
10.12.153.0/24 1; //指定网段
10.12.153.209 0; //客户端ip地址
}
map $lim $lim_key{
1 ""; //那个为空,那个是白名单,不受限制的
0 $binary_remote_addr; //根据二进制ip限制
}
limit_req_zone $lim_key zone=mylimit:10m rate=10r/s; //$lim_key调用白名单
geo块将给在白名单中的IP地址对应的$lim变量分配一个值1,给其它不在白名单中的分配一个值0。使用一个映射将这些值转为key
$lim
变量的值是1,$limit_key
变量将被赋值为空字符串$lim
变量的值是0,$limit_key
变量将被赋值为客户端二进制形式的IP地址两个指令配合使用,白名单内IP地址的$lim_key
变量被赋值为空字符串,不在白名单内的被赋值为客户端的IP地址。当limit_req_zone
后的第一个参数是空字符串时,不会应用“流量限制”,所以白名单内的不会被限制。其它所有IP地址都会被限制到每秒10个请求。
可以在一个location块中配置多个limit_req
指令。符合给定请求的所有限制都被应用时,意味着将采用最严格的那个限制。
geo $lim{
default 1; //默认
10.12.153.0/24 1; //指定网段
10.12.153.209 0; //客户端ip地址
}
map $lim $lim_key{
1 ""; //那个为空,那个是白名单,不受限制的
0 $binary_remote_addr; //根据二进制ip限制
}
limit_req_zone $lim_key zone=mylimit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=mylimit2:10m rate=5r/s;
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
limit_req zone=mylimit burst=20 nodelay;
limit_req zone=mylimit2 burst=20 nodelay;
}
}
白名单内的IP网段不会匹配到“流量限制”,但是10.12.153.209会受到mylimit2的限制,并且被限制到每秒5个请求。如果不在白名单内的IP地址两个限制能匹配到,所以应用限制更强的那个:每秒5个请求。
一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503,可以使用limit_req_status指令来设置为其它状态
geo $lim{
default 1;
10.12.153.0/24 1;
10.12.153.209 0;
}
map $lim $lim_key{
1 ""; //那个是空,那个是白名单
0 $binary_remote_addr;
}
limit_req_zone $lim_key zone=mylimit:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=mylimit2:10m rate=10r/s;
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
limit_req zone=mylimit burst=20 nodelay;
limit_req zone=mylimit2 burst=20 nodelay;
limit_req_status 520; //返回错误码改为502
}
}
默认情况下,Nginx会在日志中记录由于流量限制而延迟或丢弃的请求
默认情况下,Nginx以error级别来记录被拒绝的请求,如上面示例中的[error]所示(Ngin以较低级别记录延时请求,一般是info级别)。如要更改Nginx的日志记录级别,需要使用limit_req_log_level指令。
geo $lim{
default 1;
10.12.153.0/24 1;
10.12.153.209 0;
}
map $lim $lim_key{
1 ""; //那个是空,那个是白名单
0 $binary_remote_addr;
}
limit_req_zone $lim_key zone=mylimit:10m rate=10r/s; //流量控制1
limit_req_zone $binary_remote_addr zone=mylimit2:10m rate=10r/s; //流量控制2
server {
listen 80;
server_name localhost;
location /{
root /usr/share/nginx/html;
index index.html index.html;
limit_req zone=mylimit burst=20 nodelay; //调用流量控制1
limit_req zone=mylimit2 burst=20 nodelay; //调用流量控制2
limit_req_log_level warn; //修改被拒绝请求的日志记录级别设置为warn
}
}
例如该条日志记录
2019/02/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com"
包含的字段有:
limiting requests - 表明日志条目记录的是被“流量限制”请求
excess - 每毫秒超过对应“流量限制”配置的请求数量
zone - 定义实施“流量限制”的区域
client - 发起请求的客户端IP地址
server - 服务器IP地址或主机名
request - 客户端发起的实际HTTP请求
host - HTTP报头中host的值