https://zhuanlan.zhihu.com/p/678776165
比如系统本来可以处理1000个请求,忽然一下子来了2000个,为了不让系统崩溃,最简单的方式,就是限流,我只接1000个,超出1000个的不提供服务
#漏桶算法
一个请求在被系统处理之前,先找一个漏桶存起来,然后再以固定速率流出,比如这个漏桶可以存1000个请求,如果漏桶中有超出1000个未被处理的请求,那么这部分请求就会溢出,也就是被丢弃,比如我们常用的消息队列。
#令牌桶算法
令牌桶就是以固定的速率产生,并缓存到令牌桶中,每个请求必选先获取令牌才能系统处理,令牌桶存满的时候,多余的令牌被丢弃。
#滑动时间窗口
既然以时间为界限不行的话,我们就以时间窗口为界限,保证每个时间段内都不能超过1000qps
http {
#limit_req_zone $binary_remote_addr zone=limit_zone:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=reqlimit:64m rate=5000r/s; #参考
server {
listen 80;
server_name example.com;
location / {
#limit_req zone=limit_zone burst=20;
#limit_req zone=limit_zone burst=20 nodelay; # 不延时立即返回
limit_req zone=reqlimit burst=1000; #参考
proxy_pass http://backend;
}
}
}
参数:
limit_req_zone指令用于定义一个名为limit_zone的限流区域。
$binary_remote_addr变量表示客户端的IP地址,
zone=limit_zone:10m 表示定义一个limit_zone的10M内存区,存放限流信息
rate=10r/s 表示限制每秒处理10个请求
在location块中
limit_req 指令用于将请求限制应用于特定的URL路径。
burst=20 表示缓冲区大小20个(即等待队列),
nodelay 超过第秒10个+缓冲区20个 共30个之后的请求不延时,立即返回503错误
proxy_pass 指令用于将请求转发到后端服务器
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_zone $binary_remote_addr zone=iplimit:64m; #参考
...
server {
...
location /download/ {
# 限制一个客户端ip一个连接
limit_conn addr 1;
# 限制单个 IP 同时最多能持有 1 个连接
limit_conn perip 1;
# 限制服务器处理并发连接总数
limit_conn iplimit 5000 ;
}
}
}
我们前面看到了,限流之后有一部分的请求直接返回的503,这样对用户体验非常不好,但是我们可能有时候会看到这样的页面,比如 xx活动异常火爆,请稍后再试等提示页。或者是某个商品详情页,优先推送缓存数据而非实时数据,这就是服务降级。服务降级的核心是对非核心的,非关键的业务进行降级。
熔断这个词大家应该是熟悉的,比如家里的保险丝,当电流过大或者发生短路的时候,就会熔断,从而避免发生更大的危害。服务熔断也类似,当被调用方出现故障。调用方出于自我保护的目的,主动停止调用。为什么要主动停止调用?我之前就有过这样的经历,由于某个MySQL服务器性能的问题,执行一个SQL要好几秒。MySQL的请求越来越多,最终导致MySQL宕机,接着php的请求也越来越多,php进程打满,最终php也跟着报错。最终整个服务挂掉。
nginx,sentinel和hystrix