一 背景
在系统高可用设计中,接口限流是一个非常重要环节,一方面是出于对自身服务器资源的保护,另一方面也是对依赖资源的一种保护措施。比如对于 Web 应用,我限制单机只能处理每秒 1000 次的请求,超过的部分直接返回错误给客户端。虽然这种做法损害了用户的使用体验,但是它是在极端并发下的无奈之举,是短暂的行为,因此是可以接受的。
二 设计思路
常见的限流有2种思路
-
第一种是限制总量,也就是限制某个指标的累积上限,常见的是限制当前系统服务的用户总量,例如:某个抢购活动商品数量只有 100 个,限制参与抢购的用户上限为 1 万个,1 万以后的用户直接拒绝。
-
第二种是限制时间量,也就是限制一段时间内某个指标的上限,例如 1 分钟内只允许 10000 个用户访问;每秒请求峰值最高为 10 万。
三 限流算法
目前实现限流算法主要分为3类,这里不详细展开介绍:
1)时间窗口
固定时间窗口算法是最简单的限流算法,它的实现原理就是控制单位时间内请求的数量,但是这个算法有个缺点就是临界值问题。
为了解决临界值的问题,又推出滑动时间窗口算法,其实现原理大致上是将时间分为一个一个小格子,在统计请求数量的时候,是通过统计滑动时间周期内的请求数量。
2)漏斗算法
漏斗算法的核心是控制总量,请求流入的速率不确定,超过流量部分益出,该算法比较适用于针对突发流量,想要尽可能的接收全部请求的场景。其缺点也比较明显,这个总量怎么评估,大小怎么配置,而且一旦初始化也没法动态调整。
3)令牌桶算法
令牌桶算法的核心是控制速率,令牌产生的速度是关键,不断的请求获取令牌,获取不到就丢弃。该算法比较适用于针对突发流量,以保护自身服务资源以及依赖资源为主,支持动态调整速率。缺点的话实现比较复杂,而且会丢弃很多请求。
四 实现步骤
我们自定义的这套限流组件有是基于guava RateLimiter封装的,采用令牌桶算法以控制速率为主,支持DUCC动态配置,同时支持限流后的降级措施。接下来看一下整体实现方案
1、自定义RateLimiter Annotation标签
这里主要对限流相关属性的一个定义,包括每秒产生的令牌数、获取令牌超时时间、降级逻辑实现以及限流开关等内容
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SysRateLimit {
/**
* 每秒产生的令牌数 默认500
*
* @return
*/
double permitsPerSecond() default 500D;
/**
* 获取令牌超时时间 默认100
*
* @return
*/
long timeout() default 100;
/**
* 获取令牌超时时间单位 默认毫秒
*
* @return
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/**
* 服务降

最低0.47元/天 解锁文章
2271

被折叠的 条评论
为什么被折叠?



