【Sentinel】01-Sentinel与SpringCloud

Sentinel与SpringCloud

简介

进行服务熔断、限流

Hystrix Sentinel
单独一个组件,可以独立
界面统一管理配置

下载安装

  1. 下载地址:https://github.com/alibaba/Sentinel/tags

    img-01

    我选择的是1.7.0版本,下载地址:https://github.com/alibaba/Sentinel/releases/tag/1.7.0

  2. 启动java -jar sentinel-dashboard-1.7.0.jar

    img-03

  3. 页面访问:localhost:8080

    输入账号密码(sentinel)登录

    img-05

    进入主页

    img-06

应用

简单使用

代码

  1. 项目结构

    img-04

  2. 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
    <dependencies>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--引入sentinel依赖-->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--sentinel持久化配置-->
    <dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.5.8</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
    </dependencies>
  3. application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    server:
    port: 9041
    spring:
    application:
    name: cloud-ali-sentinel
    cloud:
    nacos:
    discovery:
    server-addr: nacos8848.com:8848
    sentinel:
    transport:
    dashboard: localhost:8080 # sentinel管理页面地址
    port: 8719 # sentinel监听所用的端口
  4. AliSentinelMain9041.java

    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
    /**
    * 1. Sentinel
    * 1.1 依赖
    * spring-cloud-starter-alibaba-sentinel
    * 1.2 配置
    * spring:
    * cloud:
    * sentinel:
    * transport:
    * dashboard: localhost:8080 # sentinel管理页面地址
    * port: 8719 # sentinel监听所用的端口
    * 1.3 启动Sentinel:sentinel-dashboard-1.7.0.jar
    * 1.4 页面:http://localhost:8080。帐号、密码:sentinel
    * @author zsq
    * @create 2021-09-07-22:51:59
    */
    @EnableDiscoveryClient
    @SpringBootApplication
    public class AliSentinelMain9041 {

    public static void main(String[] args) {
    SpringApplication.run(AliSentinelMain9041.class);
    }

    }
  5. TestController.java

    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
    @Slf4j
    @RestController
    @RequestMapping("/test")
    public class TestController {

    @Value("${server.port}")
    private Integer port;

    @GetMapping("/ok/{id}")
    public String ok(@PathVariable String id) {
    try {
    TimeUnit.MILLISECONDS.sleep(600);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    String result = "sentinel ( port = " + port + " ) - ok - id = " + id;
    log.info(result);
    return result;
    }

    @GetMapping("/no/{id}")
    public String no(@PathVariable String id) {
    String result = "sentinel ( port = " + port + " ) - no - id = " + id;
    log.info(result);
    return result;
    }

    }

sentinel客户端

上面创建的项目,引入了sentinel熔断限流的依赖。我们可以在sentinel服务的页面中,添加熔断、限流、降级配置

由于sentinel服务使用的是懒加载模式,只有接口被调用时,sentinel中才会监听到该接口。

  1. 调用http://localhost:9041/test/ok/1, http://localhost:9041/test/no/1之后,查看sentinel主页可以看到左侧菜单栏会显示服务名称,若不显示多刷新几次即可。

    img-07

  2. 实时监控:

    多调用几次接口,就可以直观看到cloud-ali-sentinel接口的实时调用情况

    img-08

  3. 簇点链路

    该页面中显示的接口,我们可以直接针对这些接口添加“限流、降级、熔断”等配置

    img-09

sentinel使用

流控

  1. 阈值类型:QPS;模式:直接;效果:快速失败

    http://localhost:9041/test/ok/1添加流控。

    因为我在代码里给/test/ok/1接口睡了600ms,将“阈值类型”改为“线程数”之后,单机阈值=1。效果与标题配置效果类似。

    img-10

    频繁调用http://localhost:9041/test/ok/1,会被Sentinel限流。效果如下:

    img-11

降级

熔断降级:Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。

当这个资源被降级之后,接下来的降级时间窗口(服务降级时间)之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)

新建熔断页面

img-12

  1. RT(平均响应时间,秒级)

    平均响应时间“超出阈值”且“在时间窗口内通过的请求数>=5”,两个条件同时满足后触发降级。

    窗口期过后关闭断路器

    RT最大4900(更大的需要通过-Dscp.sentinel.statistic.max.rt=XXXX才能生效)

  2. 异常比例(秒级)

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

  3. 异常数(分钟级)

    异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级

热点规则

同一个接口的请求中,对某一个参数值相同的请求进行限流。

可以设置参数例外项:被限制的参数值,把”5”这一值设置为参数例外项,那么不会对这个请求进行限流。

img-13

代码
  1. TestController.java添加新接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
    * SentinelResource.value 资源名称 .blockHandel 降级方法
    */
    @GetMapping("/hot_key")
    @SentinelResource(value = "hot_key", blockHandler = "hotKeyBlock")
    public String hotKey(@RequestParam(value = "p1", required = false) String p1,
    @RequestParam(value = "p2", required = false) String p2) {
    String result = "sentinel ( port = " + port + " ) - hotKey - p1 = " + p1 + ", p2 = " + p2;
    log.info(result);
    return result;
    }
    /**
    * 参数中必须加上BlockException
    * BlockException 仅负责不符合Sentinel配置的异常,运行时异常并不处理
    */
    public String hotKeyBlock(String p1, String p2, BlockException blockException) {
    String result = "sentinel.blockHandler ( port = " + port + " ) - hotKey - p1 = " + p1 + ", p2 = " + p2 + "┭┮﹏┭┮";
    log.info(result);
    return result;
    }
应用
  1. /test/hot_key接口添加热点限流,该接口的资源名hot_key

    img-14

  2. 调用http://localhost:9041/test/hot_key接口,测试结果

    此时返回了自己想要的结果

    img-15

@SentinelResource

代码
  1. TestController.java添加新接口

    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
    /**
    * 1. blockHandler Sentinel配置限流导致异常
    * 2. fallback 程序运行时异常
    */
    @GetMapping("/test")
    @SentinelResource(value = "test", blockHandler = "testBlockHandler", fallback = "testFallback")
    public String test(String name) {
    String result = "sentinel ( port = " + port + " ) - test - name = " + name;
    log.info(result);
    if (StrUtil.startWith(name, "err")) {
    throw new RuntimeException("运行时异常 --- name = " + name);
    }
    return result;
    }

    public String testBlockHandler(String name, BlockException exception) {
    String result = "sentinel.testBlockHandler ( port = " + port + " ) - test - name = " + name;
    log.info(result);
    return result;
    }

    public String testFallback(String name, Throwable throwable) {
    String result = "sentinel.testFallback ( port = " + port + " ) - test - name = " + name;
    log.info(result);
    return result;
    }
应用
  1. 测试fallback

    调用接口http://localhost:9041/test/test?name=err

  2. 结果如下

    img-16

  3. 此时在Sentinel客户端页面添加降级规则限制

    img-17

  4. 此时再调用http://localhost:9041/test/test?name=err接口时

    前两次会进入fallback,之后的5s内便会被限流

    img-18

配合feign

代码

此时,注意版本情况。Hoxton的版本若为SR1以上,项目无法启动

img-19

  1. 项目结构(cloud-ali-sentinel-feign-9051)

    img-20

  2. 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
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--引入sentinel依赖-->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--sentinel持久化配置-->
    <dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.5.8</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
    </dependencies>
  3. application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    server:
    port: 9051
    spring:
    application:
    name: cloud-ali-sentinel-feign
    cloud:
    nacos:
    discovery:
    server-addr: nacos8848.com:8848
    sentinel:
    transport:
    dashboard: localhost:8080 # sentinel管理页面地址
    port: 8719 # sentinel监听所用的端口
    feign:
    sentinel:
    enabled: true
  4. AliSentinelFeignMain9051.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @EnableDiscoveryClient
    @SpringBootApplication
    @EnableFeignClients
    public class AliSentinelFeignMain9051 {

    public static void main(String[] args) {
    SpringApplication.run(AliSentinelFeignMain9051.class);
    }

    }
  5. TestFeignController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Slf4j
    @RestController
    @RequestMapping("/feign/test")
    public class FeignTestController {

    @Resource
    private TestFeignService testFeignService;

    @GetMapping("/ok/{id}")
    public String ok(@PathVariable String id) {
    String result = "feign - ok - id = " + id;
    log.info(result);
    return testFeignService.ok(id);
    }

    @GetMapping("/no/{id}")
    public String no(@PathVariable String id) {
    String result = "feign - no - id = " + id;
    log.info(result);
    return testFeignService.no(id);
    }

    }
  6. TestFeignService.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @FeignClient(value = "cloud-ali-sentinel", fallback = TestFeignServiceImpl.class)
    public interface TestFeignService {

    @GetMapping("/test/ok/{id}")
    String ok(@PathVariable(value = "id") String id);

    @GetMapping("/test/no/{id}")
    String no(@PathVariable(value = "id") String id);

    }
  7. TestFeignServiceImpl.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Slf4j
    @Component
    public class TestFeignServiceImpl implements TestFeignService {

    @Override
    public String ok(String id) {
    String result = "feign.fallback - ok - id = " + id;
    log.info(result);
    return result;
    }

    @Override
    public String no(String id) {
    String result = "feign.fallback - no - id = " + id;
    log.info(result);
    return result;
    }

    }

应用

应用1

cloud-ali-sentinel-feign-9051服务调用cloud-ali-sentinel-9041的接口。

启动或关闭cloud-ali-sentinel-9041项目进行测试

  1. 项目cloud-ali-sentinel-9041启动时

    img-21

  2. 项目cloud-ali-sentinel-9041关闭时

    img-22

Sentinel配置持久化

以服务cloud-ali-sentinel-9041为例

  1. application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    server:
    port: 9041
    spring:
    application:
    name: cloud-ali-sentinel
    cloud:
    nacos:
    discovery:
    server-addr: nacos8848.com:8848
    sentinel:
    transport:
    dashboard: localhost:8080 # sentinel管理页面地址
    port: 8719 # sentinel监听所用的端口
    # 新增如下配置
    datasource:
    ds1:
    nacos:
    server-addr: nacos8848.com:8848
    dataId: cloud-ali-sentinel
    groupId: DEFAULT_GROUP
    data-type: json
    rule-type: flow
  2. 打开Nacos页面,添加配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [
    {
    "resource": "/test/ok/1",
    "limitApp": "default",
    "grade": 1,
    "count": 1,
    "strategy": 0,
    "controlBehavior": 0,
    "clusterMode": false
    }
    ]

    img-23

    img-24

  3. 刷新Sentinel页面可发现配置已生效

    img-25

-------------本文结束感谢您的阅读-------------