限流是常见的应用保护方案
常见限流方案
- 基于IP地址和基于服务器的访问请求限流。抵挡部分易识别的DDOS攻击,主要对request 请求头做解析判断
- QPS、并发量(连接数)限流,如Tomcat,就有最大连接数、最大请求数的设置。
- 下行带宽速率限制
限流算法
1. 令牌桶算法
单位时间内往一定容量的桶里存入令牌,令牌消耗完则时间内的请求被拒绝。 放入令牌的速度是恒定的,但是消费令牌的速度是不定的。也就是可能在流量激增的时候把令牌都消费完了导致无法访问。
基于队列实现,用队列存储令牌,每来一个请求就从队列取出一个令牌,令牌为空则拒绝请求。另一个线程稳定向队列里放入令牌,直到队列满。
2. 漏桶算法
限流更加平滑,流速是稳定的,超过流速则拒绝。消费稳定,放入流量不定。导致瞬间的流量并不会全部都消费,而是挡出去了一部分,后续新流量还是能恒定进入。
可以用FIFO队列模拟手痛,队列的容量就是水桶的最大大小,超过队列容量就拒绝,
3. 计数器算法
计数器算法是在一定时间内记录访问的次数,过了间隔就清零。比如一分钟限定能有10个访问,超过十个,拒绝访问,到了下一分钟又有10个可以访问。
单机限流可以使用内存,但是分布式集群的情况就需要引入redis。但是不能细粒度控制流量在定时区间内的平滑性,依然会有毛刺。如临界点就把两个相连区间的限定给用完了。
4. 滑动窗口算法
TCP著名的滑动窗口,滑动窗口弥补了计数器算法的不足,将大区间分成独立的小区间,只统计独立区间(黑框)的请求数量,超出独立格子的数量就会被丢弃。 我们在每一秒内有5个用户访问,第5秒内有10个用户访问,那么在0到5秒这个时间窗口内访问量就是15。如果我们的接口设置了时间窗口内访问上限是20,那么当时间到第六秒的时候,这个时间窗口内的计数总和就变成了10,因为1秒的格子已经退出了时间窗口,因此在第六秒内可以接收的访问量就是20-10=10个。
总结
|算法|优点|缺点| |令牌桶|预存一定量令牌,允许突发流量|后台系统压力大| |漏桶|对于后台系统不会有突发流量|丧失对于突发流量的处理能力| |计数器算法|简单|有临界问题,不平滑| |滑动窗口算法|优化计数器算法平滑问题|更大的内存开销|
限流层
从接入层到应用层,对应不同的部件使用不同的方式进行限流,限流的要求也不同。
- 接入层: Nginx、Openresty
- 应用网关层:SpringGateway、zuul
- 应用层:根据业务情况,由应用层自行编写限流。经典就是游戏排队,需要xxx分钟进入服务器。
限流实战
Guava Ratelimiter
流量预热,在大促或者大流量场景预测下,将令牌桶的桶容量增大以增强突发流量应对能力。 主要猎是SmoothWarmingUp,他是SmoothRateLimiter的内部类。重点是doSetRate方法。
Redis+lua
Spring Gateway
默认提供了Lua+Redis的限流服务,当Redis服务不可用时,Gateway就直接将所有请求做放行处理。
上WAF高防
Sentinel
流行的第三方限流组件,独立部署。应用引入依赖包,配置Sentinel的连接。实现Sentinel控制应用服务接口级别的限流。