当前位置:   article > 正文

Spring Boot 服务容错 Sentinel 入门_sentinelwebmvctotalconfig demo

sentinelwebmvctotalconfig demo

1. 概述

《Sentinel 极简入门》中,我们简单了解了 Sentinel,并搭建了 Sentinel 控制台。如果还没看的胖友,可以先看看该文的「1. 概述」「2. 控制台」小节。

Sentinel 功能比较强大,同时胖友可能对服务容错可能比较陌生,所以我们跟着示例,一个一个来学习噢。

2. 流量控制

示例代码对应仓库:lab-46-sentinel-demo

在本小节,我们来学习下 Sentinel 的流量控制功能,对应《Sentinel 官方文档 —— 流量控制》文章。

FROM 《Sentinel 官方文档 —— 主页》

流量控制,在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:流量控制

设计理念

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

下面,我们来搭建一个流量控制的 Spring Boot 示例。

2.1 引入依赖

在 pom.xml 文件中,引入相关依赖。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.2.2.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <modelVersion>4.0.0</modelVersion>
  12. <artifactId>lab-46-sentinel-demo</artifactId>
  13. <dependencies>
  14. <!-- 实现对 SpringMVC 的自动化配置 -->
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-web</artifactId>
  18. </dependency>
  19. <!-- Sentinel 核心库 -->
  20. <dependency>
  21. <groupId>com.alibaba.csp</groupId>
  22. <artifactId>sentinel-core</artifactId>
  23. <version>1.7.1</version>
  24. </dependency>
  25. <!-- Sentinel 接入控制台 -->
  26. <dependency>
  27. <groupId>com.alibaba.csp</groupId>
  28. <artifactId>sentinel-transport-simple-http</artifactId>
  29. <version>1.7.1</version>
  30. </dependency>
  31. <!-- Sentinel 对 SpringMVC 的支持 -->
  32. <dependency>
  33. <groupId>com.alibaba.csp</groupId>
  34. <artifactId>sentinel-spring-webmvc-adapter</artifactId>
  35. <version>1.7.1</version>
  36. </dependency>
  37. </dependencies>
  38. </project>

2.2 SpringMvcConfiguration

在 cn.iocoder.springboot.lab46.sentineldemo.config 包下,创建 SpringMvcConfiguration 配置类,自定义 sentinel-spring-webmvc-adapter 提供的拦截器。代码如下:

  1. @Configuration
  2. public class SpringMvcConfiguration implements WebMvcConfigurer {
  3. @Override
  4. public void addInterceptors(InterceptorRegistry registry) {
  5. // Add Sentinel interceptor
  6. // addSentinelWebTotalInterceptor(registry);
  7. addSentinelWebInterceptor(registry);
  8. }
  9. private void addSentinelWebInterceptor(InterceptorRegistry registry) {
  10. // <1.1> 创建 SentinelWebMvcConfig 对象
  11. SentinelWebMvcConfig config = new SentinelWebMvcConfig();
  12. config.setHttpMethodSpecify(true); // <1.2> 是否包含请求方法。即基于 URL 创建的资源,是否包含 Method。
  13. // config.setBlockExceptionHandler(new DefaultBlockExceptionHandler()); // <1.3> 设置 BlockException 处理器。
  14. // <2> 添加 SentinelWebInterceptor 拦截器
  15. registry.addInterceptor(new SentinelWebInterceptor(config)).addPathPatterns("/**");
  16. }
  17. private void addSentinelWebTotalInterceptor(InterceptorRegistry registry) {
  18. // <1> 创建 SentinelWebMvcTotalConfig 对象
  19. SentinelWebMvcTotalConfig config = new SentinelWebMvcTotalConfig();
  20. // <2> 添加 SentinelWebTotalInterceptor 拦截器
  21. registry.addInterceptor(new SentinelWebTotalInterceptor(config)).addPathPatterns("/**");
  22. }
  23. }

SentinelWebInterceptor 拦截器,针对每个 URL 进行流量控制。

  • <1.1> 处,创建 SentinelWebMvcConfig 对象,用于作为 SentinelWebInterceptor 拦截器的配置。

  • <1.2> 处,设置 是否包含请求方法。即基于 URL 创建的资源,是否包含 Method。这里有一个非常重要的概念,就是“资源”。

    FROM 《Sentinel 官方文档 —— 主页》

    资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。

    只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。 * 对于 SentinelWebInterceptor 拦截器来说,将 URL + Method 作为一个资源,进行流量控制。具体的,可以看看 SentinelWebInterceptor#getResourceName(HttpServletRequest request) 方法的代码。

  • <1.3> 处,设置 BlockException 的处理器。Sentinel 在流量控制时,当请求到达阀值后,会抛出 BlockException 异常。此时,可以通过定义 BlockExceptionHandler 去处理。这里,我们使用 SpringMVC 提供的全局异常处理机制,具体可见「2.3 GlobalExceptionHandler」

  • <2> 处,添加 SentinelWebInterceptor 拦截器到 InterceptorRegistry 中。

SentinelWebTotalInterceptor 拦截器,针对全局 URL 进行流量控制。简单来说,所有 URL 合计流量,全局统一进行控制。

  • <1> 处,创建 SentinelWebMvcTotalConfig 对象,用于作为 SentinelWebTotalInterceptor 拦截器的配置。
  • <2> 处,添加 SentinelWebTotalInterceptor 拦截器到 InterceptorRegistry 中。

2.3 GlobalExceptionHandler

在 cn.iocoder.springboot.lab46.sentineldemo.web 包下,创建 GlobalExceptionHandler 配置类,自定义 sentinel-spring-webmvc-adapter 提供的拦截器。代码如下:

  1. @ControllerAdvice(basePackages = "cn.iocoder.springboot.lab46.sentineldemo.controller")
  2. public class GlobalExceptionHandler {
  3. @ResponseBody
  4. @ExceptionHandler(value = BlockException.class)
  5. public String blockExceptionHandler(BlockException blockException) {
  6. return "请求过于频繁";
  7. }
  8. }

2.4 DemoController

在 cn.iocoder.springboot.lab46.sentineldemo.controller 包下,创建 DemoController 类,提供稍后测试流量控制的示例 API。代码如下:

  1. @RestController
  2. @RequestMapping("/demo")
  3. public class DemoController {
  4. @GetMapping("/echo")
  5. public String echo() {
  6. return "echo";
  7. }
  8. @GetMapping("/test")
  9. public String test() {
  10. return "test";
  11. }
  12. }

2.5 Sentinel 配置文件

在 resources 目录下,创建 Sentinel 自定义的sentinel.properties 配置文件。内容如下:

csp.sentinel.dashboard.server=127.0.0.1:7070

2.6 Application

创建 Application.java 类,配置 @SpringBootApplication 注解即可。代码如下:

  1. @SpringBootApplication
  2. public class Application {
  3. public static void main(String[] args) {
  4. // <X> 设置系统属性 project.name,提供给 Sentinel 读取
  5. System.setProperty("project.name", "demo-application");
  6. // 启动 Spring Boot 应用
  7. SpringApplication.run(Application.class, args);
  8. }
  9. }
  • 在 <X> 处,设置系统属性 project.name,提供给 Sentinel 读取。比较特殊,该配置项无法在 csp.sentinel.dashboard.server 配置文件中设置。

2.7 简单测试

启动 Spring Boot 应用。

① 使用浏览器,访问下 http://127.0.0.1:8080/demo/echo 接口。因为 Sentinel 客户端是懒加载的。此时,控制台输出日志如下:

  1. INFO: log output type is: file
  2. INFO: log charset is: utf-8
  3. INFO: log base dir is: /Users/yunai/logs/csp/
  4. INFO: log name use pid is: false

② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。此时,我们可以看到 demo-application 应用。如下图所示:Sentinel 控制台 - 首页

③ 使用浏览器,访问下 http://127.0.0.1:8080/demo/echo 接口 10 次。然后点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口的请求情况。如下图所示:Sentinel 控制台 - 实时监控

④ 点击 Sentinel 控制台的「簇点链路」菜单,可以看到 GET:/demo/echo 资源。如下图所示:Sentinel 控制台 - 簇点链路

⑤ 点击 GET:/demo/echo 资源所在列的「流控」按钮,弹出「新增流控规则」。填写流控规则,如下图所示:Sentinel 控制台 - 新增流控规则

  • 这里,我们创建的是比较简单的规则,仅允许 GET:/demo/echo 资源被每秒调用一次。更多详细的配置项的说明,胖友后续一定要认真看《Sentinel 官方文档 —— 流量控制》文章,这是 Sentinel 提供的多种规则中最最最常用的一种。

⑥ 点击「新增」按钮,完成流控规则的添加。此时,会自动跳转到「流控规则」菜单。如下图所示:Sentinel 控制台 - 流控规则

⑦ 使用浏览器,访问 http://127.0.0.1:8080/demo/echo 接口两次,会有一次被 Sentinel 流量控制而拒绝,最终返回 "请求过于频繁"

此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:Sentinel 控制台 - 实时监控

3. 熔断降级

示例代码对应仓库:lab-46-sentinel-demo

在本小节,我们来学习下 Sentinel 的流量控制功能,对应《Sentinel 官方文档 —— 熔断降级》文章。

FROM 《Sentinel 官方文档 —— 主页》

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。熔断降级

设计理念

Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。

Hystrix 通过 线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。

Sentinel 对这个问题采取了两种手段:

1、通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

2、通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

下面,我们来搭建一个熔断降级的 Spring Boot 示例。本着省时省力(努力偷懒)的原则,我们直接复用「2. 流量控制」小节的 lab-46-sentinel-demo 项目。

3.1 DemoController

在 DemoController 类中,额外添加 demo/sleep 接口,通过 sleep 100 毫秒,模拟延迟较高的接口。代码如下:

  1. @GetMapping("/sleep")
  2. public String sleep() throws InterruptedException {
  3. Thread.sleep(100L);
  4. return "sleep";
  5. }

3.2 简单测试

重新启动 Spring Boot 应用。

友情提示:咱会发现之前配置的流量控制规则不见了,不要慌,后面会详细述说。

① 使用浏览器,访问下 http://127.0.0.1:8080/demo/sleep 接口。因为 Sentinel 客户端是懒加载的。

② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。

然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 GET:/demo/sleep 资源。

之后,点击 GET:/demo/sleep 资源所在列的「降级」按钮,弹出「新增降级规则」。填写降级规则,如下图所示:Sentinel 控制台 - 新增降级规则

  • 这里,我们创建的是比较简单的规则,当 GET:/demo/sleep 资源在 5 秒的时间窗口中,如果平均响应时间超过 1 ms,则进行熔断降级。

Sentinel 一共有 3 种方式来衡量资源是否稳定:

FROM 《Sentinel 官方文档 —— 流量控制》

1、平均响应时间 (DEGRADE_GRADE_RT)

当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。
注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

2、异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO)

当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

3、异常数 (DEGRADE_GRADE_EXCEPTION_COUNT)

当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。

③ 点击「新增」按钮,完成降级规则的添加。此时,会自动跳转到「降级规则」菜单。如下图所示:Sentinel 控制台 - 降级规则

④ 使用浏览器,访问 http://127.0.0.1:8080/demo/sleep 接口 6 次,就会有被 Sentinel 服务降级而拒绝,最终返回 "请求过于频繁"

此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:Sentinel 控制台 - 实时监控

耐心等待几秒,过了这个时间窗口后,继续访问 http://127.0.0.1:8080/demo/sleep 接口,又可以成功返回了。

4. 热点参数限流

示例代码对应仓库:lab-46-sentinel-demo

在本小节,我们来学习下 Sentinel 的热点参数限流功能,对应《Sentinel 官方文档 —— 热点参数限流》文章。

FROM 《Sentinel 官方文档 —— 热点参数限流》

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制。
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制。

热点参数限流,会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。热点参数限流

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

下面,我们来搭建一个热点参数限流的 Spring Boot 示例。本着省时省力(努力偷懒)的原则,我们继续复用「2. 流量控制」小节的 lab-46-sentinel-demo 项目。

4.1 引入依赖

在 pom.xml 文件中,额外引入相关依赖。

  1. <!-- Sentinel 对【热点参数限流】的支持 -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-parameter-flow-control</artifactId>
  5. <version>1.7.1</version>
  6. </dependency>
  7. <!-- Sentinel 对 Spring AOP 的拓展 -->
  8. <dependency>
  9. <groupId>com.alibaba.csp</groupId>
  10. <artifactId>sentinel-annotation-aspectj</artifactId>
  11. <version>1.7.1</version>
  12. </dependency>
  • 引入 sentinel-parameter-flow-control 依赖,实现 Sentinel 对【热点参数限流】的支持。
  • 引入 sentinel-annotation-aspectj 依赖,实现 Sentinel 对 Spring AOP 的推展。稍后我们会使用到 Sentinel 提供的 @SentinelResource 注解声明自定义资源,通过 Spring AOP 拦截该注解的方法,从而实现自定义资源的 Sentinel 的处理逻辑。

4.2 DemoController

在 DemoController 类中,额外添加 demo/product_info 接口,用于热点参数限流的示例 API。代码如下:

  1. @GetMapping("/product_info")
  2. @SentinelResource("demo_product_info_hot")
  3. public String productInfo(Integer id) {
  4. return "商品编号:" + id;
  5. }
  • 在方法上,我们添加了 @SentinelResource 注解,自定义了 demo_product_info_hot 资源。

为什么不直接使用 sentinel-spring-webmvc-adapter 库,自动给该 demo/product_info 接口生成的 GET:/demo/product_info 呢?

  • 原因:因为 sentinel-spring-webmvc-adapter 库提供的 SentinelWebInterceptor 和 SentinelWebTotalInterceptor 拦截器在调用 Sentinel 客户端时,并未传入参数,所以无法进行热点参数限流。
  • 解决:使用 @SentinelResource 注解,自定义了 demo_product_info_hot 资源。然后,通过 Spring AOP 拦截该方法的调用,实现 Sentinel 的处理逻辑。在本小节中,就是为了热点参数限流。

4.3 简单测试

重新启动 Spring Boot 应用。

① 使用浏览器,访问下 http://127.0.0.1:8080/demo/product_info?id=1 接口。因为 Sentinel 客户端是懒加载的。

② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。

然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 demo_product_info_hot 资源。

之后,点击 demo_product_info_hot 资源所在列的「热点」按钮,弹出「新增热点规则」。填写热点规则,如下图所示:Sentinel 控制台 - 新增热点规则

  • 这里,我们只设置了参数索引为 0,统计窗口时长为 60 秒,请求最大次数为 10。更多设置,我们继续往下看。

③ 点击「新增」按钮,完成热点规则的添加。此时,会自动跳转到「热点规则」菜单。如下图所示:Sentinel 控制台 - 热点规则

之后,点击 demo_product_info_hot 资源所在列的「编辑」按钮,弹出「编辑热点规则」。填写热点规则,如下图所示:Sentinel 控制台 - 编辑热点规则

  • 这里,我们配置了当第一个参数的值为 1 时,限制在统计窗口中,请求最大次数为 1。

点击「 保存」按钮,完成编辑。

④ 使用浏览器,访问 http://127.0.0.1:8080/demo/product_info?id=1 接口 2 次,就会有被 Sentinel 热点参数限流而拒绝,最终返回 "请求过于频繁"

此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:Sentinel 控制台 - 实时监控

此时,我们访问 http://127.0.0.1:8080/demo/product_info?id=2 接口,不会存在限流的情况。而是在快速访问 10 次,才会被限流。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/889155
推荐阅读
相关标签