限流、熔断
1.限流
1.1 定义
概念: 限制服务方接口调用流量,对服务端的请求进行限制。
限流的原因可能有很多,如突发热点事件导致服务请求QPS过高,导致服务器性能不足;限制用户某些操作的频次,如接口被刷等。
限流有时候是为了让自己服务不被打垮,有时候是为了让别人服务不被打垮;
此处列举一个常见的限流场景:
- ATM机输入3次密码错误,则提示你明天才能操作。这就是一种限流操作,限制24小时3次错误,则返回限流提示信息。
1.2 限流算法
1.2.1 计数器算法
- 原理:在单位时间内,对请求数进行累加,与阈值进行比较,达到阈值则限流;到时间临界点,计数清零。
- 缺点:1)系统收到大量请求冲击,可能超出系统的承受预期; 2) “突刺现象”:配置10s<5次,如果1s5次,后4秒等着,不平滑;
- 实现:基于 Redis 的 incr 原子操作及Expires key 过期机制,用户每访问一次,incr实现+1,若val=1,则重新设置过期时间;
public void rateLimit(String conditionKey, LimiterConfig limiterConfig) {
LimiterConfig config = Apollo.getConfig(limiterConfig);
if (config == null) {
return;
}
Long count = redisTemplate.opsForValue().increment(condition, Constant.IntegerNumber.ONE);
if (Constant.LongNumber.ONE.equals(count)) {
redisTemplate.expire(condition, config.getTimeCycle(), TimeUnit.SECONDS);
}
if (count > detail.getLimitValue()) {
log.error("rateLimit operating frequently");
throw new LimitException(ResponseCodeEnum.OPERATING_FREQUENTLY);
}
}
1.2.2 漏桶算法
- 原理:水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口响应频率),当水流入速度过大会直接溢出(访问频率超过接口响应频率),然后就拒绝请求,可以看出漏桶算法能强行限制数据的传输速率;
- 缺点:因为漏桶的漏出速率是固定的参数,所以即使网络没有发生拥塞,漏桶算法也不能使流量突发(burst)到端口速率。
1.2.3 令牌桶算法
- 原理:系统按恒定速率1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token,如果桶已经满了就不再加了。新请求来临时,会各自拿走一个Token,如果没有Token可拿了就阻塞或者拒绝服务;
- 优点:1) 可以方便的改变速度,一旦需要提高速率,则按需提高放入桶中的令牌的速率;
1.2.4 使用场景
并不能认为令牌桶一定比漏桶好,使用场景不一样。
- 令牌桶可以用来保护自己,主要用来对调用者频率进行限流,为的是让自己不被打垮。所以如果自己本身有处理能力的时候,如果流量突发(实际消费能力强于配置的流量限制),那么实际处理速率可以超过配置的限制。
- 漏桶算法,可以用来保护我们所调用的系统。主要场景是,当调用的第三方系统本身没有保护机制,或者有流量限制的时候,我们的调用速度不能超过他的限制,由于我们不能更改第三方系统,所以只有在主调方控制。这个时候,即使流量突发,也必须舍弃。因为消费能力是第三方决定的。
总结:
- 如果为了保证自己的系统不被打垮,用令牌桶算法;
- 如果为了保证别人的系统不被打垮,用漏桶算法。
1.3 限流粒度
- 服务调用方:按照某个业务方进行限流;
- ip:按照ip限流(此时需要注意代理的问题);
- 接口:可以按照某个接口进行限流;
2. 熔断、降级
2.1 定义
概念:
区别:熔断和降级有什么区别?
- 服务熔断一般是某个下游服务故障引起,而服务降级一般是从整体负荷考虑。
2.2 熔断实现方式
AOP,符合条件则熔断
3. 主流框架
3.1 Sentinal(Alibaba)
Sentinal官方文档
3.2 Hystrix(SpringClould)
Hystrix官方文档
3.3 Resilience4j
Resilience4j官方文档