限流存在于高可用服务中。
用于高可用的保护手段,主要包括:缓存,降级,限流
限流:只允许指定的事件进入系统,超过的部分将被拒绝服务,排队或者降级处理。
一:服务扛不住压力了
二:因为资源的稀缺或者处于安全防范的目的而采用的自我保护机制,保证有限的资源提供最大的服务能力,按照预期的流量提供服务 ,超过的部分将会拒绝服务,排队或者降级处理
通用及最简单的算法,简单逻辑是维护一个固定时间的计数器,如果检测到单位时间过去则记为0,重新计数
存在的问题
1.没有应对突发的流量的能力:如100的qps,前100ms来了99个,后900ms只能处理一个
2.不准确,在一个窗口内后半段时间来了100个请求,以及在后一个窗口的前半段时间100个请求,等同于在一个窗口内出现了双倍的限流的流量!
水:请求
桶:限流阈值大小
漏的水滴:固定速率,服务的处理速度
实现步骤:
1.将每个请求放入固定的大小的队列进行存储
2.以固定的速率向外流出请求,队列为空则停止流出
3.队列满了则拒绝服务
为了保证网站在遭受流量攻击的时候,仍然能够保障正常用户的访问不受到影响,有必要对网站添加限流措施。通过简单的配置Nginx,可以帮助我们实现这一功能。
优点:令牌桶支持突发流量
因为桶中有多少令牌在等待,就允许有多少突发请求可以执行
实现步骤:
1.以恒定的速率向桶中增加令牌
2.如果令牌满了直接丢弃,如果有请求则获取令牌进行请求
3.如果桶空了,则拒绝执行
实现服务限流的方式有很多种,下面我主要介绍的是Nginx实现,优点是不用频繁部署jar服务,减少代码编写。提高效率,短时间解决问题
Nginx支持通过以下维度,来对用户的请求进行限制:
对应Nginx模块:ngx_http_limit_req_module
# 限流设置,这只是设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。具体的限制需要定义具体的url
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=10r/s;
# 指定错误码
limit_req_status 429;
server {
location /update_content {
proxy_pass http://192.168.211.1:18081;
}
location /read_content {
# 使用限流配置
limit_req zone=contentRateLimit;
proxy_pass http://192.168.211.1:18081;
}
}
超过流量不会立即被拒绝,允许加入一个队列,只有队列满了之后的请求才会被拒绝。如果有时正常流量突然增大,超出的请求将被拒绝,无法处理突发流量,就可以结合 burst 参数使用来解决该问题。
# 限流设置,这只是设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。具体的限制需要定义具体的url
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=10r/s;
server {
location /update_content {
proxy_pass http://192.168.211.1:18081;
}
location /read_content {
# 使用限流配置
limit_req zone=contentRateLimit burst=4 nodelay;
proxy_pass http://192.168.211.1:18081;
}
}
Nginx内置的limit_conn_zone和limit_conn指令,提供了通过限制ip连接数来控制流量的能力。
其中只有当服务器正在处理请求并且已经读取了整个请求头时,才会计算为有效连接。
对应Nginx模块:ngx_http_limit_conn_module
(1) 控制每个IP的连接数
limit_conn_zone $binary_remote_addr zone=perip:10m;
server {
location /brand {
# 同一个地址只允许连接2次
limit_conn perip 2;
proxy_pass http://192.168.211.1:18081;
}
}
limit_conn_zone $binary_remote_addr zone=perip:10m :表示根据用户的IP地址来进行限制,设置共享内存大小为10M。
limit_conn perip 2 :表示同一个地址只允许连接2次。
(2) 控制与服务器的连接总数
# 根据server_name来限制,存储内存大小10M
limit_conn_zone $server_name zone=perserver:10m;
server {
listen 80;
server_name xx.com;
location / {
# 限制与服务器的总连接数
limit_conn perserver 100;
root html;
index index.html index.htm;
}
}
limit_conn_zone $server_name zone=perserver:10m :表示根据用户访问的server_name来进行限制,设置共享内存大小为10M。
limit_conn perserver 100 :表示同一个server只允许连接100次。
设置http请求传输多少字节后开始限速。
对应Nginx模块:ngx_http_core_module
location /flv/ {
limit_rate_after 500k;
# 带宽限制,对单个连接限速
limit_rate 50k;
}
limit_rate_after 500k :表示传输的前500k数据不限速,500k之后再进行限速。
limit_rate 50k :对单个连接限速为50k/s。如果一个客户端发起两个连接,就是50k * 2。
配置固定IP为黑名单,访问时会返回403 Forbidden。
nginx 是按照自上而下的顺序进行匹配,匹配到一个就不往下继续了,如遇到 return 指令时 return 指令还是会生效。
server {
listen 8080;
server_name _;
location / {
allow 192.168.135.1;
deny all;
return 200 "$remote_addr 正常访问 3";
}
}
# 屏蔽单个ip访问
deny IP;
# 允许单个ip访问
allow IP;
# 屏蔽所有ip访问
deny all;
# 允许所有ip访问
allow all;
# 屏蔽整个段即从123.0.0.1到123.255.255.254访问的命令
deny 123.0.0.0/8
# 屏蔽IP段即从123.45.0.1到123.45.255.254访问的命令
deny 124.45.0.0/16
# 屏蔽IP段即从123.45.6.1到123.45.6.254访问的命令
deny 123.45.6.0/24
# 也可以通过配置文件来配置
include blockip.conf;
动态黑白名单:也可以采用Lua+Redis实现,将黑名单存入到Redis缓存,每次执行请求时,通过lua脚本先获取用户IP,匹配IP是否属于黑名单,如果是,则不让请求,如果不是,则放行。
/**
* provide by zym
* 0 error(s), 0 warning(s)
*/