限流
tomcat限流的几种方式:
计数器,滑动窗口,漏桶法,令牌桶
为什么要限流
短时间内流量一大,服务器就扛不住了,扛不住就挂了,挂了没法提供对外服务导致业务直接熔断。最直接的方法是从源头把流量限制下来,例如服务器只有支撑100QPS的处理能力,就只能每秒处理100个请求,保持服务器的稳定。
- 业务用户量不断攀升
- 各种促销活动
- 网络爬虫
- 恶意刷单
漏桶算法
Nginx的限流模块就是基于漏桶算法的,它最大的特点就是强行限制流量按照指定的比例下发,适合那种对流量有绝对要求的场景,就是流量可以容许在我指定的值之下,可以被多次打回,但是无论如何决不能超过指定的。
把请求当做水先进入一个漏桶中,认为设置一个最大出水速率,漏桶以小于等于出水速率的速度出水,当水流入速度过大会直接溢出(拒绝服务)
算法核心:
- 存下请求
- 匀速处理
- 多余丢弃
这是一种强行限制请求速率的方式,实际场景下用得不多。但是有两个明显的缺点:
- 无法处理突发的大流量,网络中经常可能短时间突发一大波大流量,但是处理速度不够,多余的请求全部被丢弃,服务器拒绝服务。
- 无法有效利用网络资源----比如虽然服务器的处理能力是1000/s,但这不是绝对的,这个1000只是一个宏观服务器处理能力的数字,实际上一共5秒,每秒请求量分别为1200、1300、1200、500、800,平均下来qps也是1000/s,但是这个量对服务器来说完全是可以接受的,但是因为限制了速率是1000/s,因此前面的三秒,每秒只能处理掉1000个请求而一共打回了700个请求,白白浪费了服务器资源
令牌桶算法
令牌桶算法是网络流量整形和限流中最常使用的一种算法,可用于控制网络上数据的数量并允许突发数据的发送。
令牌桶算法是对漏桶算法的一种改进,主要在于令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。
令牌桶算法执行过程:
- 系统以恒定的速率产生令牌,然后将令牌放入令牌桶中
- 令牌桶有一个容量,当令牌桶满了的时候,再向其中放入的令牌就会被丢弃
- 每次一个请求过来,需要从令牌桶中获取一个令牌,假设有令牌,那么提供服务;假设没有令牌,那么拒绝服务
假设我们想要的速率是1000QPS,那么往桶中放令牌的速度就是1000个/s,假设第1秒只有800个请求,那意味着第2秒可以容许1200个请求,这就是一定程度突发流量的意思,反之我们看漏桶算法,第一秒只有800个请求,那么全部放过,第二秒这1200个请求将会被打回200个。
注意上面多次提到一定程度这四个字,这也是我认为令牌桶算法最需要注意的一个点。假设还是1000QPS的速率,那么5秒钟放1000个令牌,第1秒钟800个请求过来,第2~4秒没有请求,那么按照令牌桶算法,第5秒钟可以接受4200个请求,但是实际上这已经远远超出了系统的承载能力,因此使用令牌桶算法特别注意设置桶中令牌的上限即可。
作为对漏桶算法的改进,令牌桶算法在限流场景下被使用更加广泛。
计数器
- 对所有用户的访问次数计数。定义一个计时器,单位为一分钟。如果超过次数,就拒绝该请求。一分钟后,次数刷新值为0
private Map<String, List> map = new ConcurrentHashMap<>();
- 使用aop实现请求的限制, 在需要限制的请求方法上加上aop逻辑。
自定义注解类 实现 请求限制的拦截逻辑, 在需要限制的方法上使用注解,超出限制后拒绝处理请求。