在 Nginx 中,我们经常会遇到这种情况,服务器流量异常,负载过大等等。对于大流量恶意的攻击访问,会带来带宽的浪费,服务器压力,影响业务,往往考虑对同一个 ip 的连接数,并发数进行限制。http_limit_conn_module 模块来实现。
该模块可以根据定义的键来限制每个键值的连接数,如同一个 IP 来源的连接数。并不是所有的连接都会被该模块计数,只有那些正在被处理的请求(这些请求的头信息已被完全读入)所在的连接才会被计数。
http_limit_req_module 模块来实现,该模块可以通过定义的 键值来限制请求处理的频率。特别的,可以限制来自单个 IP 地址的请求处理频率。 限制的方法如同漏斗,每秒固定处理请求数,推迟过多请求。
limit_conn_zone $variable zone=name:size;
http
该指令描述会话状态存储区域。键的状态中保存了当前连接数,键的值可以是特定变量的任何非空值(空值将不会被考虑)。$variable 定义键,zone=name 定义区域名称,后面的 limit_conn 指令会用到的。size 定义各个键共享内存空间大小。如:
limit_conn_zone $binary_remote_addr zone=addr:10m;
客户端的 IP 地址作为键。注意,这里使用的是 $binary_remote_addr 变量,而不是 $remote_addr 变量。
$remote_addr 变量的长度为 7 字节到 15 字节,而存储状态在 32 位平台中占用 32 字节或 64 字节,在 64 位平台中占用 64 字节。
$binary_remote_addr 变量的长度是固定的 4 字节,存储状态在 32 位平台中占用 32 字节或 64 字节,在 64 位平台中占用 64 字节。
1M 共享空间可以保存 3.2 万个 32 位的状态,1.6 万个 64 位的状态。如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。
limit_zone 指令和 limit_conn_zone 指令同等意思,已经被弃用,就不再做说明了。
limit_req_zone $variable zone=name:size rate=rate;
http
设置一块共享内存限制域用来保存键值的状态参数。 特别是保存了当前超出请求的数量。 键的值就是指定的变量(空值不会被计算)。如:
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
区域名称为 one,大小为 10m,平均处理的请求频率不能超过每秒一次。键值是客户端 IP。
使用 $binary_remote_addr 变量, 可以将每条状态记录的大小减少到 64 个字节,这样 1M 的内存可以保存大约1 万 6 千个 64 字节的记录。
如果限制域的存储空间耗尽了,对于后续所有请求,服务器都会返回 503 (Service Temporarily Unavailable)错误。
速度可以设置为每秒处理请求数和每分钟处理请求数,其值必须是整数,所以如果你需要指定每秒处理少于 1 个的请求,2 秒处理一个请求,可以使用 “30r/m”。
我们首先使用 vim 打开 nginx 的默认配置路径,具体命令如下:
vim /etc/nginx/conf.d/default.conf
如下图所示:
我们执行如上命令,打开配置文件,接着,我们修改 server 下面的根路径的 location 配置,具体配置如下:
limit_conn_zone $binary_remote_addr zone=conn_zone:1m;
limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
配置完毕后,如下图所示:
现在,我们重新加载配置文件,具体命令如下:
nginx -s reload
现在,我们使用 ab 命令,进行压力测试,具体命令如下:
ab -n 40 -c 20 http://127.0.0.1/
执行完毕后,如下图所示:
我们看到,完成了 40 个请求,现在,我们修改配置如下:
limit_conn_zone $binary_remote_addr zone=conn_zone:1m;limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s;server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; #limit_conn conn_zone 1; #limit_req zone=req_zone burst=3 nodelay; #limit_req zone=req_zone burst=3; limit_req zone=req_zone; index index.html index.htm; }}
请求限制打开,重新加载 Nginx 配置,1s 同一个客户端只允许连接一次,我们再次进行测试,具体命令如下:
ab -n 40 -c 20 http://127.0.0.1/
执行完毕后,如下图所示:
我们看到,失败了 39 个,只成功了一个,即,我们的限制生效了。
在 Nginx 中,我们经常会遇到这种情况,服务器流量异常,负载过大等等。对于大流量恶意的攻击访问,会带来带宽的浪费,服务器压力,影响业务,往往考虑对同一个 ip 的连接数,并发数进行限制。