常见的限流算法

1. 为什么需要限流

以服务的调用方来看,可以分为两种类型服务:对外提供的服务(web服务)、对内提供的服务(微服务之间调用)

对外提供的服务有以下几种可能导致机器被拖垮:

  • 用户增长过快
  • 热点事件
  • 爬虫
  • 刷单

对内提供服务:

一个服务A的接口假如被BCDE等多个服务进行调用,如果B服务发生突发流量,就会直接把A服务调用挂了,会导致CDE无法正常使用。解决方案:

  • 每个调用方采用线程池进行资源隔离(避免资源被耗尽无法分配资源)
  • 使用限流手段对每个调用方进行限流

2. 限流方式

常见的限流有:限制总并发数(比如数据库连接池、线程池)、限制瞬时并发数(如 nginx 的 limit_conn 模块,用来限制瞬时并发连接数)、限制时间窗口内的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率);其他还有如限制远程接口调用速率、限制 MQ 的消费速率。另外还可以根据网络连接数、网络流量、CPU 或内存负载等来限流。

常见的限流纬度有比如通过Ip来限流、通过uri来限流、通过用户访问频次来限流。

一般限流都是在网关这一层做,比如Nginx、Openresty、kong、zuul、Spring Cloud Gateway等;也可以在应用层通过Aop这种方式去做限流。

 

3. 限流算法

常见的限流算法有:计数器、令牌桶、漏桶。

3.1 计数器算法

需求:假设规定,对于 A 接口,1分钟的访问次数不能超过100个。

实现方案:设置一个计数器 counter,每当一个请求过来的时候,counter 就加 1,如果 counter 的值大于100并且该请求与第一个请求的间隔时间还在1分钟之内,那么说明请求数过多;如果该请求与第一个请求的间隔时间大于1分钟,且 counter 的值还在限流范围内,那么就重置 counter,可以使用 AtomicLong#incrementAndGet() 实现。

问题:临界问题:比如在前一秒的最后一毫秒里和下一秒的第一毫秒都触发了最大的请求数,也就是在两毫秒内发生了两倍的 TPS。突刺问题:如果在单位时间1s内的前10ms,已经通过了100个请求,那后面的990ms,只能把请求拒绝,这种现象称为“突刺现象”。用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。

解决方案:滑动窗口,将时间窗口进行多段划分,当时间到达1:00时,我们的窗口会往右移动一格,每一个格子都有自己独立的计数器counter,此时分析时间窗口内的总请求数量一共是200个,超过了限定的100个,所以此时能够检测出来触发限流。

 

3.2 漏桶算法

漏桶算法实现限流可以解决突刺现象。当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。如果桶满了,那么新进来的请求就丢弃。

算法实现:可以用一个队列,用来保存请求,另外通过一个线程池(ScheduledExecutorService)来定期从队列中获取请求并执行,可以一次性获取多个并发执行。

弊端:无法应对短时间的突发流量。因为漏桶的漏出速率是固定的参数,所以,即使网络中不存在资源冲突(没有发生拥塞),漏桶算法也不能使流突发(burst)到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。

 

3.3 令牌桶算法

从某种意义上讲,令牌桶算法是对漏桶算法的一种改进, 漏桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。

实现思路:存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择等待可用的令牌、或者直接拒绝。

算法实现过程:放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,比如设置 qps 为100,那么限流器初始化完成一秒后,桶中就已经有100个令牌了,等启动完成对外提供服务时,该限流器可以抵挡瞬时的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。

算法实现:可以准备一个队列,用来保存令牌,另外通过一个线程池定期生成令牌放到队列中,每来一个请求,就从队列中获取一个令牌,并继续执行。

开源实现Google开源的guava包

4. 集群限流

通过外部计算器比如Redis,比如需要限制某个用户访问/query接口的次数,只需要拼接用户id和接口名生成redis的key,每次该用户访问此接口时,只需要对这个key执行incr命令,在这个key带上过期时间,就可以实现指定时间的访问频率。



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值