Spring Cloud Sentinel-学习笔记.md

image-20211130112225875

介绍

Sentinel是Hystrix的替代谢解决方案

官网:https://sentinelguard.io/zh-cn/

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

  • 支持双十一10年
  • 完备的实时监控
  • 比hystrix好用

总体框架如下

image-20211130141525199

Sentinel分为两个部分

  • 核心库(java控制端)
  • 控制台(Dashboard) 基于Spring Boot开发,打开后可直接运行

搭建控制台

下载控制台:https://sentinelguard.io/zh-cn/docs/dashboard.html

https://github.com/alibaba/Sentinel/tree/master/sentinel-dashboard4

  • 下载sentinel

  • E:\DBank\软件\开发软件\sentinel

  • 启动命令

    1
    java -Dserver.port=18558 -Dcsp.sentinel.dashboard.server=localhost:18558 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar
  • 登陆 sentinel 账号密码都是登陆

创建项目

操作列表

  • 添加依赖spring-cloud-alibaba-dependencies 2.2.6.RELEASE

  • 添加依赖spring-cloud-starter-alibaba-sentinel

  • 配置文件中开启feign的sentinel依赖支持

  • 配置文件中开启cloud的sentinel 支持已经port端口

配置内容

  • application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    server:
    port: ${SERVICE_PORT:18780}
    compression: # 開啓壓縮請求
    enabled: true
    mime-types: application/json,application/xml,text/html,text/xml,text/plain
    spring:
    application:
    name: order-sentinel
    jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
    show-sql: false
    hibernate:
    naming:
    physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    ddl-auto: update
    datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://localhost:4306/eurekademo
    cloud:
    inetutils:
    ignoredInterfaces: ['VMware.*','ingress'] # 必须过滤掉VMware 因为会豁达86.1
    preferred-networks:
    - ${NET_DOMAIN:192.168/16} #必须只选择192网段的否则会选择一些虚拟机网卡\
    sentinel:
    transport:
    port: 17780 # 端点端口
    dashboard: localhost:18055 #sentinel dashboard
    eureka:
    client:
    register-with-eureka: false # 将自己注册到注册中心 默认 true
    fetch-registry: true # 是否从注册中心获取服务注册信息 默认true
    service-url:
    defaultZone: http://root:123456@localhost:18761/eureka/,http://root:123456@localhost:18762/eureka/,http://root:123456@localhost:18763/eureka/
    registry-fetch-interval-seconds: 10 # 表示 eureka Client 间隔多久去服务器拉取注册信息,默认为 30 秒。
    feign:
    sentinel:
    enabled: true # 开启sentinel
    client:
    config:
    default:
    connectTimeout: 3000
    readTimeout: 3000
    loggerLevel: basic
  • pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
    <groupId>org.akachi</groupId>
    <artifactId>eurekademo</artifactId>
    <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.akachi.eurekademo</groupId>
    <artifactId>order-sentinel</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>order-sentinel</name>
    <description>Demo project for Spring Boot</description>
    <properties>
    <java.version>11</java.version>
    <spring-cloud.version>2020.0.4</spring-cloud.version>
    <spring-boot.version>2.5.5</spring-boot.version>
    <netflix-eureka-server.version>3.0.4</netflix-eureka-server.version>
    <openfeign.version>3.0.4</openfeign.version>
    <spring-alibaba.version>2.2.6.RELEASE</spring-alibaba.version>
    </properties>
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>${netflix-eureka-server.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    <version>8.0.26</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>${openfeign.version}</version>
    </dependency>
    <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.11</version>
    </dependency>
    <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>10.7.4</version>
    </dependency>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>${spring-alibaba.version}</version>
    </dependency>
    </dependencies>
    <dependencyManagement>
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>${spring-cloud.version}</version>
    <type>pom</type>
    <scope>import</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>${spring-alibaba.version}</version>
    <type>pom</type>
    </dependency>
    </dependencies>
    </dependencyManagement>
    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    </project>
  • SentinelApplication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package org.akachi.eurekademo.sentinel;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;

    /**
    * @Author akachi
    * @Email zsts@hotmail.com
    * @Date 2021/11/30 16:33
    */
    @EnableFeignClients
    @SpringBootApplication
    public class SentinelApplication {
    public static void main(String[] args) {
    SpringApplication.run(SentinelApplication.class, args);
    }

    }

资源

  • 启动 sentinel-dashboard-1.8.2.jar

客户端怎么监控

  1. 添加依赖

    • org.springframework.cloud spring-cloud-starter-alibaba-sentinel
    • 父工程添加 org.springframework.cloud spring-cloud-alibaba-dependencies
  2. 接入config

    1
    2
    3
    4
    5
    6
    7
    8
    9
    spring:
    cloud:
    sentinel:
    transport:
    port: 17780 # 端点端口
    dashboard: localhost:18055 #sentinel dashboard
    feign:
    sentinel:
    enabled: true # 开启sentinel

流控LoadBalanced

  • pom.xml

    1
    2
    3
    4
    5
    6
      
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-netflix-ribbon</artifactId>
    <version>2.2.6.RELEASE</version>
    </dependency>

定义@SentinelResource 在资源头上就是方法头上

  • blockHandlerClass 是指触发限流调用的类

  • fallbackClass 降级调用那个类

  • 埋点方法不支持public,这是feing试验失败

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
      
    public List<Product> productsBlockHandler(BlockException cause){
    cause.printStackTrace();
    Product product = new Product();
    List<Product> productList = new ArrayList();
    productList.add(product);
    product.setName("兜底数据");
    product.setCode("-1");
    return productList;
    }

    @Override
    @SentinelResource(value="OrderProductServiceImpl.products",blockHandler="productsBlockHandler")
    public List<Product> getProducts() {
    ResponseEntity<List<Product>> responseEntity = restTemplateBalancer.exchange(
    "http://EUREKADEMO-SERVICE-PRODUCT/product/list",
    HttpMethod.GET,
    null,
    new ParameterizedTypeReference<List<Product>>() {
    });
    return responseEntity.getBody();
    }
  • 会在 dashboard上看到内容

    image-20211206130704686

  • 限制方式可以是

    • 流量控制

    • 降级

      降级的方法要在最后加入Throwable才行

    • 热点限流(根据参数限流)

      image-20211206133636368

      • 0是第一个参数
    • 授权(允许谁访问不允许谁访问)

      1
      2
      3
      4
      5
      6
      7
      @Component
      public class OrderRequestOriginParser implements RequestOriginParser {
      @Override
      public String parseOrigin(HttpServletRequest request) {
      return request.getParameter("userName");
      }
      }

      通过一个继承RequestOriginParser的类获得请求中的一个字段来进行限流

      访问 http://localhost:18780/order/list?userName=akachi

      出发限流

动态规则配置

为了保证不要从其配置不会丢失,需要使用动态规则扩展

支持:

  • 文件配置
  • Nacose
  • ZooKeeper
  • Apollo
  • Redis

image-20211206141914799

配置一个文件配置规则

Field 说明 默认值
resource 资源名称对应代码中的
count 限流阈值
grade 限流模式 QPS(1) 并发或线程(0) QPS模式
limitApp 流控关系限流策略 default,代表不区分调用来源
controlerBehavior 留控效果(直接拒绝/排队等待/慢启动模式) 直接拒绝
clusterMode 是否集群限流
strategy 调用关系策略: 直接、链路、关联 根据资源本身(直接)
  • 配置flowRule.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [
    {
    "resource": "OrderProductServiceImpl.products",
    "count": 1,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0,
    "controlBehavior": 0
    }
    ]
  • application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    spring:
    cloud:
    sentinel:
    datasource:
    ds1:
    file:
    file: classpath:flowRule.json
    data-type: json
    rule-type: flow
  • 效果

    image-20211206145639293

基于Rest Template进行限流

  • 编写一个ExceptionUtil类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    package org.akachi.eurekademo.sentinel.util;

    import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
    import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.alibaba.fastjson.JSON;
    import org.akachi.eurekademo.product.model.Product;
    import org.springframework.http.HttpRequest;
    import org.springframework.http.client.ClientHttpRequestExecution;
    import org.springframework.http.client.ClientHttpResponse;

    import java.util.ArrayList;
    import java.util.List;

    /**
    * @Author akachi
    * @Email zsts@hotmail.com
    * @Date 2021/12/6 15:16
    */
    public class SentinelExceptionUtil {
    public static ClientHttpResponse handleException(HttpRequest request,
    byte[] body,
    ClientHttpRequestExecution exception,
    BlockException blockException) {
    blockException.printStackTrace();
    Product product = new Product();
    List<Product> productList = new ArrayList();
    productList.add(product);
    product.setName("限流处理-兜底数据");
    product.setCode("-1");
    return new SentinelClientHttpResponse(JSON.toJSONString(productList));
    }

    public static ClientHttpResponse fallback(HttpRequest request,
    byte[] body,
    ClientHttpRequestExecution exception,
    BlockException blockException) {
    blockException.printStackTrace();
    return new SentinelClientHttpResponse("Throwable-熔断降级");
    }
    }
  • 在RestTemplate的@Bean 下面加入注解@SentinelRestTemplate

    1
    2
    3
    4
    5
    @SentinelRestTemplate(blockHandler = "handleException",
    fallback = "fallback",
    fallbackClass = SentinelExceptionUtil.class,
    blockHandlerClass = SentinelExceptionUtil.class
    )

最后针对OpenFeign支持

Sentinel对于OpenFeign支持,核心代码是一致的,基本上修改依赖与配置文件即可。

  • 添加依赖 pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
      
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>${openfeign.version}</version>
    </dependency>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>${spring-alibaba.version}</version>
    </dependency>
  • 配置文件 application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    feign:
    sentinel:
    enabled: true # 开启sentinel
    spring:
    cloud:
    sentinel:
    transport:
    port: 17780 # 端点端口
    dashboard: localhost:18055 #sentinel dashboard

参考文档