https://github.com/alibaba/Sentinel/wiki/

Sentinel基本概念

资源:只要通过Sentinel API定义的代码,就是资源,能够被Sentinel保护起来。大部分情况,可以使用方法签名,URL,服务名称作为资源名来标示资源。
规则:包括流量控制规则、熔断降级规则、系统保护规则。所有规则可以用动态实行调整。

Sentinel工作主流程

Spring Cloud Alibaba整合Sentinel

引入依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-actuator</artifactId>
  8. </dependency>

配置yml

  1. server:
  2. port: 8800
  3. spring:
  4. application:
  5. name: mall-user-sentinel-demo
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: 139.198.123.65:8848
  10. sentinel:
  11. transport:
  12. # 添加sentinel控制台
  13. dashboard: localhosts:8080
  14. # 指定应用于sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
  15. # port: 8719

Sentinel控制台

运行 sentinel-dashboard jar 包

流控规则

image.png

  • 资源名:api接口
  • 针对来源:默认default,当多个微服务都调用这个资源时,可以对配置微服务名来对指定的微服务设置阈值
  • 阈值类型:QPS与线程数 如:单机阈值为10

    • QPS:每秒访问资源次数>10进行限流
    • 线程数:接收请求该资源的线程数>10进行限流

      直接

      资源请求达到阈值后直接抛出异常

      关联

      如果关联资源超出阈值,则当前资源会被限流。
      /user/info/{id}访问的QPS超过2,则/user/findOrderbByUserId/{id}会被限流,/user/info/{id}不会被限流。
      image.png

      链路

      屌代码有bug。

      1. <!--- 解决流控链路不生效的问题-->
      2. <dependency>
      3. <groupId>com.alibaba.csp</groupId>
      4. <artifactId>sentinel-web-servlet</artifactId>
      5. </dependency>
      1. @Configuration
      2. public class SentinelConfig {
      3. @Bean
      4. public FilterRegistrationBean sentinelFilterRegistration() {
      5. FilterRegistrationBean registration = new FilterRegistrationBean();
      6. registration.setFilter(new CommonFilter());
      7. registration.addUrlPatterns("/*");
      8. // 入口资源关闭聚合 解决流控链路不生效的问题
      9. registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
      10. registration.setName("sentinelFilter");
      11. registration.setOrder(1);
      12. return registration;
      13. }
      14. }

      继续报错
      image.png

      public class SentinelConfig {
      @Bean
      public FilterRegistrationBean sentinelFilterRegistration() {
         FilterRegistrationBean registration = new FilterRegistrationBean();
         registration.setFilter(new CommonFilter());
         registration.addUrlPatterns("/*");
         // 入口资源关闭聚合   解决流控链路不生效的问题
         registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
         registration.setName("sentinelFilter");
         registration.setOrder(1);
      
         //CommonFilter的BlockException自定义处理逻辑
         WebCallbackManager.setUrlBlockHandler(new MyUrlBlockHandler());
         return registration;
      }
      }
      
      @Slf4j
      public class MyUrlBlockHandler implements UrlBlockHandler {
      @Override
      public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
         log.info("UrlBlockHandler BlockException================" + e.getRule());
      
         R r = null;
      
         if (e instanceof FlowException) {
             r = R.error(100, "接口限流了");
      
         } else if (e instanceof DegradeException) {
             r = R.error(101, "服务降级了");
      
         } else if (e instanceof ParamFlowException) {
             r = R.error(102, "热点参数限流了");
      
         } else if (e instanceof SystemBlockException) {
             r = R.error(103, "触发系统保护规则了");
      
         } else if (e instanceof AuthorityException) {
             r = R.error(104, "授权规则不通过");
         }
      
         //返回json数据
         response.setStatus(500);
         response.setCharacterEncoding("utf-8");
         response.setContentType(MediaType.APPLICATION_JSON_VALUE);
         new ObjectMapper().writeValue(response.getWriter(), r);
      }
      }
      
      @Override
      @SentinelResource(value = "getUser", blockHandler = "handleException")
      public OrderEntity getUser(Integer id) {
         OrderEntity user = baseMapper.selectById(id);
         return user;
      }
      public OrderEntity handleException(int id, BlockException ex) {
         OrderEntity userEntity = new OrderEntity();
         userEntity.setUserId("===被限流降级啦===");
         return userEntity;
      }
      

      如果入口资源访问getUser超过了阈值,则会被限流。免费版的这个功能有bug,不建议用。
      image.png

      流控效果

      快速失败

      当QPS超过任意规则的阈值后,新请求会被拒绝,抛出FolwException

      Warm Up

      给定冷系统预热时间,避免冷系统被压垮。冷加载因子,codeFactor默认是3,请求从threshold/3开始,经过预热时长,逐渐升至设置的QPS
      image.png
      前5秒,每秒访问3次,后面慢慢递增到10次。

      排队等待

      会严格控制请求的间隔时间。
      image.png
      每秒通过10个请求, 请求超时500ms会被拒绝。

      降级规则

      熔断策略

      慢调用比例

      image.png
      最大RT为慢请求的ms数。
      当慢请求的比例大于0.2,并且在单位时间内的请求大于5条,在接下来三秒将会熔断。

      异常比例

      image.png
      接口异常的比例超过0.4,并且单位时长的请求数超过5,将会在接下来的3秒对资源进行熔断。

      异常数

      image.png
      接口异常的数量超过5,并且单位时长的请求数超过5,将会在接下来的3秒对资源进行熔断。

      热点规则

      image.png
      该资源传参第一个值为1的阈值为2,其他阈值为3.
      接口格式:

      @RequestMapping("/info/{id}")
      @SentinelResource(value = "userinfo",
             blockHandlerClass = CommonBlockHandler.class,
             blockHandler = "handleException2",
             fallbackClass = CommonFallback.class,
             fallback = "fallback")
      public R info(@PathVariable("id") Integer id) {
         OrderEntity user = orderService.getById(id);
      
         if (id == 4) {
             throw new IllegalArgumentException("异常参数");
         }
      
         return R.ok().put("user", user);
      }
      

      系统规则

      从整体的维度对应用流量进行控制。
      image.png

      授权规则

      @Component
      public class MyRequestOriginParser implements RequestOriginParser {
      /**
      * 通过request获取来源标识,交给授权规则进行匹配
      *
      * @param request
      * @return
      */
      @Override
      public String parseOrigin(HttpServletRequest request) {
         // 标识字段名称可以自定义
             String origin = request.getParameter("serviceName");
      //        if (StringUtil.isBlank(origin)){
      //            throw new IllegalArgumentException("serviceName参数未指定");
      //        }
         return origin;
      }
      }
      
      @Bean
      public FilterRegistrationBean sentinelFilterRegistration() {
         FilterRegistrationBean registration = new FilterRegistrationBean();
         registration.setFilter(new CommonFilter());
         registration.addUrlPatterns("/*");
         // 入口资源关闭聚合   解决流控链路不生效的问题
         registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
         registration.setName("sentinelFilter");
         registration.setOrder(1);
      
         //CommonFilter的BlockException自定义处理逻辑
         WebCallbackManager.setUrlBlockHandler(new MyUrlBlockHandler());
      
         //解决授权规则不生效的问题
         //com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser
         WebCallbackManager.setRequestOriginParser(new MyRequestOriginParser());
         return registration;
      }
      

      image.png

      Sentinel整合OpenFeign

      开启Sentinel对feign的支持

      feign:
      sentinel:
      enabled: true