nginx提供2种限流的方式:
- 一是控制速率
- 二是控制并发连接数
控制速率
控制速率的方式之一采用漏桶算法
1.1漏桶算法实现控制速率限流
漏桶算法的思路很简单,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率,示意图如下:
限流是解决雪崩的有效手段之一
1.2nginx的配置
配置示意图如下:
修改nginx.conf
#限流设置 binary_remote_addr:根据IP请求进行限流 contentRateLimit:缓存空间名称 10m:缓存空间
#rate=2r/s : 每秒允许2个请求被处理
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;
#使用限流配置
limit_req zone=contentRateLimit;
1.3配置完成后 重启nginx
1.4配置burst,将请求加入队列
burst译为突发,爆发,表示在超过设定的处理速率后能额外处理的请求数,当rate=10r/s,将拆分为10份,即100ms可处理1个请求。
此处,burst=4,若同时又4个请求到达,Nginx会处理第一个请求,剩余3个请求将放回队列,然后每隔500ms从队列中获取一个请求进行处理。若请求数大于4,将拒绝处理多余的请求,直接返回503.
代码如下:
server {
listen 80;
#监听的域名
server_name localhost;
location /update_content {
content_by_lua_file /root/lua/68/update_content.lua;
}
#表示所有以 localhost/read_content的请求都由该配置处理
location /read_content {
limit_req zone=contentRateLimit burst=4;
content_by_lua_file /root/lua/68/read_content.lua;
}
}
不过,单独使用burst参数并不实用,假设burst=50,rate依然为10r/s,排队中的50个请求虽然 每隔100ms会处理一个,但是第50个请求却需要等待50*100ms即5s,这么长的处理时间难以接受。
因此,burst往往结合nodelay一起使用。
1.5配置nodelay 将所有参数并行处理
如下配置:
server {
listen 80;
#监听的域名
server_name localhost;
location /update_content {
content_by_lua_file /root/lua/68/update_content.lua;
}
#表示所有以 localhost/read_content的请求都由该配置处理
location /read_content {
limit_req zone=contentRateLimit burst=4 nodelay;
content_by_lua_file /root/lua/68/read_content.lua;
}
}
表示平均每秒允许不超过2个请求,突发不超过4个请求,并且处理突发4个请求的时候,没有延迟,等到完成后,按照正常的速率处理。
1.6如上两种配置结合就达到了速率的稳定,完整配置代码如下:
user root root;
worker_processes 1;
error_log logs/error.log debug;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#定义Nginx缓存模块,模块名字叫dis_cache,容量大小128M
lua_shared_dict dis_cache 128m;
#限流设置
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
#监听的域名
server_name localhost;
location /update_content {
content_by_lua_file /root/lua/68/update_content.lua;
}
#表示所有以 localhost/read_content的请求都由该配置处理
location /read_content {
limit_req zone=contentRateLimit burst=4 nodelay;
content_by_lua_file /root/lua/68/read_content.lua;
}
}
}
2.控制并发量(连接数)
ngx_http_limit_conn_module 提供了限制连接数的能力,主要是利用limit_conn_zone 和limit_conn两个指令。
利用连接数限制 某一用户的ip连接的数量来控制流量
注意:并非所有连接都被计算在内,只有当服务器正在处理请求已经读取了整个请求头时,才会计算有效连接,此处忽略测试
配置语法:
Syntax : limit_conn zone number
Default : -;
Context :http , server , location;
在controller里休眠10秒
@GetMapping
public Result<List<Brand>> findAll(){
try{
System.out.println("准备睡觉:"+Thread.currentThread().getId());
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
//调用BrandService实现查询所有Brand
List<Brand> list = brandService.findAll();
return new Result<List<Brand>>(true, StatusCode.OK,"查询成功",list) ;
}
// A code block
var foo = 'bar';
2.1配置限制固定连接数
如下:
location /brand{
proxy_pass http://192.168.0.103:18081;
}
配置限流:
#根据IP地址来限制,存储内存大小10M
limit_conn_zone $binary_remote_addr zone=addr:10m;
location /brand{
limit_conn addr 2;
proxy_pass http://192.168.0.103:18081;
}
测试:此时开3个线程会发生异常,开2个不会有异常
2.2限制每个客户端IP与服务器的连接数,同时限制于虚拟机服务的连接总数
如下配置:
#个人IP显示
limit_conn_zone $binary_remote_addr zone=perip:10m;
#针对整个服务所有的并发量控制
limit_conn_zone $server_name zone=perserver:10m;
location /brand{
#limit_conn addr 5;
#个人IP限流配置
limit_conn perip 3;
#当前location的总并发量配置
limit_conn perserver 5;
proxy_pass http://192.168.0.103:18081;
}