暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

浅谈sentinel限流

轻聊浅谈闲码 2020-12-30
1634

1.常见限流算法

计数器算法

在指定周期内累加访问次数,当访问次数达到阈值时触发限流,当进入下一个时间周期时进行访问次数的清零。
问题:临界问题,相邻两个周期时间段内访问次数可能超出限制,但并未限流。

滑动窗口算法

在固定窗口中分割出多个小时间窗口,然后根据时间将窗口向前滑动并删除过期的小时间窗口,最终只统计滑动窗口范围内的所有小时间窗口总的计数。

令牌桶限流算法
  • 固定大小的令牌桶(即限制最大请求量)

  • 系统以恒定速度(r token/sec)往令牌桶中放入令牌

  • 客户端请求执行前需要先获取并消耗令牌桶中的令牌

  • 当请求速度大于令牌生成速度,令牌会被很快消耗,从而达到限流效果

问题:短时间内的突发流量无法处理

漏桶限流算法
  • 内部维护一个容器

  • 容器以恒定速度流出流量

  • 当请求速度大于容器流出速度,则会触发限流

2.服务熔断

当服务无法提供正常服务时,为了防止雪崩效应,暂时将出现故障的接口隔离开来,后续一段时间调用的请求直接失败,直到目标服务恢复正常。
判断指标:平均响应时长,异常比例,异常数量

3.服务降级

将一些不重要的业务或接口的功能降低,可以只提供部分功能,也可以完全停掉所有不重要的功能。

4.Sentinel dashboard安装

启动命令

  1. java -jar sentinel-dashboard.jar

  2. -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080

  3. -Dcsp.sentinel.dashboard.server=localhost:8080 用于控制台对外暴露的服务地址

  4. -Dproject.name=sentinel-dashboard 项目名称

  5. -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;

  6. -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel;

  7. -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;

5.Sentinel实现流量限制

定义规则
  1. List<FlowRule> rules = new ArrayList()<>;

  2. FlowRule rule = new FlowRule();

  3. // 资源名

  4. rule.setResource(“resource1”);

  5. // 限流阈值类型,QPS模式1,并发线程模式2

  6. rule.setGrade(RuleConstant.FLOW_GRADE_QPS);

  7. // 是否根据来源进行限流,默认未default,即不区分

  8. rule.setLimitApp(“default”);

  9. // 调用关系限流策略,直接,链路,关联

  10. rule.setStrategy(RuleConstant.STRATEGY_CHAIN);

  11. // 流控行为,直接拒绝,排队等待,慢启动模式,默认直接拒绝

  12. rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);

  13. // 是否为集群限流

  14. rule.setClusterMode(false);

  15. // 限流阈值

  16. rule.setCount(20);

  17. rules.add(rule);

  18. FlowRuleManager.loadRules(rules);

限流
  1. try (Entry entry = SphU.entry(“resource1”)) {

  2. // 业务逻辑

  3. } catch (BlockException e) {

  4. // 限流会抛出BlockException

  5. }

注解形式
  1. @SentinelResource(value = resourceName”, blockHandler = blockHandlerForResource1”)

Grade属性

FLOW_GRADE_THREAD(统计当前请求的上下文线程数量)
FLOW_GRADE_QPS(统计每秒查询数)

QPS流量控制行为

直接拒绝
Warm Up(冷启动(预热)):系统并不是直接将QPS限制拉到最大,而是逐步增加阈值
匀速排队:严格控制请求通过的间隔时间,也就是让请求以匀速的速度通过,类似于漏桶限流算法

调用关系流量策略
  • 调用方限流:
    根据请求来源进行流量控制,需要设置limitApp属性来设置来源信息
    default:表示不区分调用者,也就是任何访问调用者的请求都会进行限流统计
    {some_origin_name}:设置特定的调用者,只有来自这个调用者的请求才会进行流量统计和控制
    other:表示针对除{some_origin_name}外的其他调用者进行流量控制

  • 根据调用链路入口限流:

  • 关联流量控制:两个资源之间存在关联时,只限制其中一个资源

6.Sentinel实现服务熔断

  1. List<DegradeRule> rules = new ArrayList()<>;

  2. DegradeRule rule = new DegradeRule();

  3. // 资源名

  4. rule.setResource(“resource1”);

  5. // 熔断策略

  6. rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

  7. // 限流阈值

  8. rule.setCount(10);

  9. // 触发熔断降级后多长时间内自动熔断,单位s

  10. rule.setTimeWindow(10);

  11. // 触发熔断的最小请求数,请求数小于该值时即使异常比例超过阈值也不会触发熔断,默认5

  12. rule.setMinRequestAmount(5);

  13. // Grade为RT时,1s内持续多少个请求平均RT超出阈值触发熔断,默认5

  14. rule.setRtSlowRequestAmount(5);

  15. rules.add(rule);

三种熔断策略:
  • 平均响应时间(RuleConstant.DEGRADE_GRADE_RT)
    如果1s内持续进入5个请求,对应的平均响应时间都超过了阈值(count,单位ms)那么接下来的时间窗口(timeWindow,单位s)内,进行自动熔断,抛出DegradeException

  • 异常比例(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
    如果每秒资源数 >= minRequestAmount(默认5),并且每秒异常占比超过阈值count(count的取值范围[0.0,1.0],代表0%到100%),则进行熔断…

  • 异常数(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT)
    当资源最近一分钟的异常数目超过阈值后,触发熔断

7.热点数据限流

  1. List<ParamFlowRule> rules = new ArrayList()<>;

  2. ParamFlowRule rule = new ParamFlowRule(“resource1”);

  3. // 热点参数的索引

  4. rule.setParamIdx(0);

  5. // 限流阈值类型,QPS模式1,并发线程模式2

  6. rule.setGrade(RuleConstant.FLOW_GRADE_QPS);

  7. // 限流阈值

  8. rule.setCount(20);

  9. rules.add(rule);

  10. ParamRuleManager.loadRules(rules);

8.使用

客户端引入依赖
  1. <dependency>

  2. <groupId>com.alibaba.cloud</groupId>

  3. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>

  4. <version>2.1.1.RELEASE</version>

  5. </dependency>

yml配置:
  1. spring:

  2. cloud:

  3. sentinel:

  4. transport:

  5. dashboard: localhost:9100

配置规则

阈值类型/单机阈值:

  • QPS:每秒的请求量达到阈值,进行限流

  • 线程数:当调用该api的线程数达到阈值时进行限流

流控模式:

  • 直接:api达到限流条件时,直接限流

  • 关联:当关联的资源达到阈值时,就限流自己

  • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流,但其它入口进来的不会限流)


熔断策略:

  • RT:平均响应时间(秒级统计)超出阈值 且 在时间窗口内的请求 >= 5时,触发降级(断路器打开);时间窗口结束后,关闭降级【Sentinel默认最大的RT为4900ms,可以通过-Dcsp.sentinel.statistic.max.rt=xxx修改】

  • 异常比例:QPS >= 5 且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

  • 异常数:异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级【时间窗口 < 60秒可能会出现问题】
    关于异常数这种降级策略需要注意的点:
    若将时间窗口的值设置小于60秒则可能会出问题,因为异常数的统计是分钟级别的,时间窗口小于60秒就有可能不断进入降级状态.
    spring cloud sentinel 处理的场景是 feign 远程调用的降级异常 tracer 记录了。
    普通异常需要手动加Tracer.trace(e);

需要自己添加资源@SentinelResource(value = “resourceName”)

参数例外项:指定参数值进行额外限流

  • LOAD:(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps minRt 计算得出。设定参考值一般是 CPU cores 2.5

  • RT:当单台机器上所有入口流量的平均 RT(响应时间) 达到阈值即触发系统保护,单位是毫秒

流控应用(limitApp)指的时调用方的服务名

自定义限流异常
  1. @Component

  2. @Slf4j

  3. public class MyBlockHandler implements BlockExceptionHandler {


  4. @Override

  5. public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {

  6. if (e instanceof FlowException) {

  7. log.error("限流异常");

  8. } else if (e instanceof DegradeException) {

  9. log.error("降级异常");

  10. } else if (e instanceof ParamFlowException) {

  11. log.error("热点参数异常");

  12. } else if (e instanceof SystemBlockException) {

  13. log.error("系统异常");

  14. } else if (e instanceof AuthorityException) {

  15. log.error("授权异常");

  16. }

  17. httpServletResponse.setStatus(HttpStatus.OK.value());

  18. R r = R.fail(ErrorCode.SENTINEL.getCode(), e.getMessage());

  19. httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");

  20. httpServletResponse.getWriter().print(JSON.toJSONString(r));

  21. httpServletResponse.getWriter().flush();

  22. }

  23. }

文章转载自轻聊浅谈闲码,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论