前言
我们经常会遇到这种情况,服务器流量异常,负载过大等等。对于大流量恶意的攻击访问,会带来带宽的浪费,服务器压力,影响业务,往往考虑对同一个ip的连接数,并发数进行限制。下面说说ngx_http_limit_conn_module
模块来实现该需求。该模块可以根据定义的键来限制每个键值的连接数,如同一个IP来源的连接数。并不是所有的连接都会被该模块计数,只有那些正在被处理的请求(这些请求的头信息已被完全读入)所在的连接才会被计数。
访问限制模块
limit_conn_zone
- 语法:
limit_conn_zone $variable zone=name:size;
- 默认值:
no
- 使用字段:
http
- $variable定义键
指令描述会话状态存储区域,键的状态中保存了当前连接数。
会话的数目按照指定的变量来决定,它依赖于使用的变量大小和memory_max_size
的值。
例子:
limit_conn_zone $binary_remote_addr zone=one:10m;
解释:
- zone=one 表示设置了名为“one”的存储区,大小为10兆字节
- $binary_remote_addr表示客户端的IP地址作为键
- $binary_remote_addr变量的长度是固定的4字节,存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。
- 1M共享空间可以保存3.2万个32位的状态,1.6万个64位的状态。 如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。
limit_conn
- 语法:
limit_conn zone_name number
- 默认值:
none
- 配置段:
http, server, location
指定每个给定键值的最大同时连接数,当超过这个数字时被返回503 (Service Temporarily Unavailable)错误。
例子:
server {
location / {
limit_conn one 3;
}
}
解释: 同一IP同一时间只允许有3个连接。
限制访问频率模块
limit_req_zone
- 语法:
limit_req_zone $session_variable zone=name:size rate=rate
- 默认值:
none
- 上下文:
http
命令解析:为session会话状态分配一个大小为size的内存存储区,限制了每秒(分、小时)只接受rate个IP的频率。
例子:
limit_req_zone $binary_remote_addr zone=allips:10m rate=5r/s;
解释:
- zone=allips表示设置了名为“allips”的存储区,大小为10M。
- rate=5r/s 的意思是允许1秒钟不超过5个请求
limit_ewq
- 语法:
limit_req zone=name burst=burst [nodelay]
- 默认值:
none
- 使用字段:
http、server、location
命令解析:该指令用于指定使用的内存存储区(zone
)名称,以及最大的突发请求数(burst
)。如果请求的速率超过了limit_req_zone
指令中设置的速率,这些请求将被延迟处理,在这种情况下,请求获得服务不可用信息,返回503状态码。
例子:
limit_req zone=allips burst=10 nodelay;
解释:
- burst=10 最大延迟请求数量不大于10,
- nodelay 请求不需要被延迟,超过最大延迟请求数量的服务器会立刻返回503状态码。如果没有该字段会造成大量的tcp连接请求等待。
实际应用
如果作为代理服务器,我们需要限制每个用户的请求速度和链接数量,但是,由于一个页面有多个子资源,如果毫无选择的都进行限制,那就会出现很多不必要的麻烦,如:一个页面有40个子资源,那么如果想让一个页面完整的显示,就需要将请求速度和连接数都调整到40,以此达到不阻塞用户正常请求,而这个限制,对服务器性能影响很大,几百用户就能把一台nginx的处理性能拉下来。
所以我们需要制定哪些请求是需要进行限制的,如html页面;哪些是不需要限制的,如css、js、图片等,这样就需要通过配置对应的location进一步细化。
我们不对css、js、gif、png,jpg等进行连接限制,而对除此之外的链接进行限制。
http {
···
limit_conn_zone $binary_remote_addr zone=one:10m;
limit_req_zone $binary_remote_addr zone=allips:10m rate=5r/s;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location ~ .*\.(gif|png|css|js|icon)$ {
proxy_set_header Host $http_host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* .*\.(jpeg|jpg|JPG)$ {
proxy_set_header Host $http_host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root html;
index index.html index.htm;
#limit
limit_conn one 3;
limit_req zone=allips burst=10 nodelay;
}
}
···
}
这个配置的含义就是指定一个IP地址只用同时存在一个连接,一个IP地址一秒钟只处理5个请求,最大的突发请求数可以到10,请求速率超过或者会话存储区慢都将返回503。
测试
使用ab
进行测试:
ab -n 11 -c 1 http://192.168.241.134/
没有失败请求。
ab -n 12 -c 1 http://192.168.241.134/
出现一条失败请求。