Spring Cloud Alibaba 服务容错 Sentinel 入门
1. 概述本文我们来学习Spring Cloud Alibaba提供的Spring Cloud Alibaba Sentinel组件,对 Spring Cloud 进行整合,实现服务容错相关的功能。FROMhttps://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentine
1. 概述
本文我们来学习 Spring Cloud Alibaba 提供的 Spring Cloud Alibaba Sentinel 组件,对 Spring Cloud 进行整合,实现服务容错相关的功能。
FROM https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
- 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
在开始本文之前,胖友需要对 Sentinel 进行简单的学习。可以阅读《Sentinel 极简入门》文章,将第一二小节看完,在本机搭建一个 Sentinel 控制台。
友情提示:艿艿本机搭建的 Sentinel 控制台启动在 7070 端口。
2. 流量控制
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
在本小节,我们来学习下 Sentinel 的流量控制功能,对应《Sentinel 官方文档 —— 流量控制》文章。
流量控制,在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
设计理念
流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
- 运行指标,例如 QPS、线程池、系统负载等;
- 控制的效果,例如直接限流、冷启动、排队等。
Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。
下面,我们来搭建一个 Sentinel 流量控制的使用示例。最终示例项目如下图所示:
2.1 引入依赖
在 pom.xml
文件中,引入 Spring Cloud Alibaba Sentinel 相关依赖。
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-04</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-04-sca-sentinel-demo01-provider</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Sentinel 相关依赖,使用 Sentinel 提供服务保障,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
通过引入 spring-cloud-starter-alibaba-sentinel
依赖,引入并实现 Sentinel 的自动配置。在该依赖中,已经帮我们自动引入 Sentinel 的大量依赖,非常方便,如下图所示:
2.2 配置文件
创建 application.yaml
配置文件,添加 Sentinel 配置项。配置如下:
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置项,对应 SentinelProperties 配置属性类
sentinel:
enabled: true # 是否开启。默认为 true 开启
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
filter:
url-patterns: /** # 拦截请求的地址。默认为 /*
Sentinel 配置项,以 spring.cloud.sentinel
开头,对应 SentinelProperties 配置属性类。
① enabled
配置项,设置是否开启 Sentinel,默认为 true
开启,所以一般不用主动设置。如果胖友关闭 Sentinel 的功能,例如说在本地开发的时候,可以设置为 false
关闭。
② eager
配置项,设置是否饥饿加载,默认为 false
关闭。默认情况下,Sentinel 是延迟初始化,在首次使用到 Sentinel 才进行初始化。通过设置为 true
时,在项目启动时就会将 Sentinel 直接初始化,完成向 Sentinel 控制台进行注册。
③ transport.dashboard
配置项,设置 Sentinel 控制台地址。
④ filter.url-patterns
配置项,设置拦截请求的地址,默认为 /*
。
在 Sentinel 的子项目 sentinel-spring-webmvc-adapter
中,对 SpringMVC 进行适配,通过 SentinelWebInterceptor 拦截器,实现对 SpringMVC 的请求的拦截,使用 Sentinel 进行保护。通过 filter.url-patterns
配置项,可以定义该拦截器的拦截请求地址。
不过要注意,因为 filter.url-patterns
配置项的默认值为 /*
,只能拦截根目录的请求,显然不满足我们的日常需求,因此艿艿修改成了 /**
拦截所有请求。不了解的胖友,可以阅读下《SpringMVC Ant 路径匹配》文章。
2.3 BlockException 处理器
先来对 BlockException 异常做个简单的了解,在被 Sentinel block 的时候,就会抛出它。BlockException 是一个异常抽象基类,其有 5 个实现类,刚好对应 Sentinel 的 5 种流量控制手段,如下图所示:
旁白君:暂时找不到 block 适合翻译成什么单词,相对最贴切的可能是阻塞...
在 SentinelWebInterceptor 拦截器中,当请求满足配置的 Sentinel block 的条件时,Sentinel 会抛出 BlockException 异常。通过定义 BlockExceptionHandler 接口的实现类,可以实现对 BlockException 的异常处理。
默认情况下,BlockExceptionHandler 有一个默认的 DefaultBlockExceptionHandler 实现类,返回 Block 字符串提示。代码如下:
public class DefaultBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
// ... 省略其它代码
PrintWriter out = response.getWriter();
out.print("Blocked by Sentinel (flow limiting)");
}
}
显然,在我们使用 SpringMVC 提供 Restful API 时,直接返回字符串提示是不合适的,因为一般是返回 JSON 字符串,例如说:
{
"code": 1024,
"msg": "Blocked by Sentinel (flow limiting)"
}
因此,我们自定义的 CustomBlockExceptionHandler 实现类,直接抛出 BlockException 异常,最终交给自定义的 SpringMVC 全局异常处理器 ,将 BlockException 异常处理成 JSON 字符串提示返回。代码如下:
// CustomBlockExceptionHandler.java
@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
throw e;
}
}
// GlobalExceptionHandler.java
@Component
@ControllerAdvice(basePackages = "cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider") // 只处理该包下的 Controller 定义的接口
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(value = BlockException.class) // 因为这里是示例,所以暂时使用 JSONObject,实际项目最终定义一个 CommonResult。
public JSONObject blockExceptionHandler(BlockException blockException) {
return new JSONObject().fluentPut("code", 1024)
.fluentPut("msg", "请求被拦截,拦截类型为 " + blockException.getClass().getSimpleName());
}
}
友情提示:如果胖友对 SpringMVC 的全局异常处理器不了解的话,可以看看《芋道 Spring Boot SpringMVC 入门》文章的「5. 全局异常处理」小节。
2.4 DemoController
创建 DemoController 类,提供稍后测试流量控制的示例 API。代码如下:
@RestController
@RequestMapping("/demo")
public class DemoController {
@GetMapping("/echo")
public String echo() {
return "echo";
}
@GetMapping("/test")
public String test() {
return "test";
}
}
2.5 DemoProviderApplication
创建 DemoProviderApplication 类,作为应用启动类。代码如下:
@SpringBootApplication
public class DemoProviderApplication {
public static void main(String[] args) {
SpringApplication.run(DemoProviderApplication.class, args);
}
}
2.6 简单测试
① 使用 DemoProviderApplication 启动示例应用。在 IDEA 控制台中,可以看到 Sentinel 相关的日志如下:
// ... 省略其它日志
// Sentinel 初始化。有点不合群的日志格式~
INFO: log output type is: file
INFO: log charset is: utf-8
INFO: log base dir is: /Users/yunai/logs/csp/
INFO: log name use pid is: false
// 注册 SentinelWebInterceptor 拦截器,拦截路径为 /** 的请求
2020-02-13 23:30:05.574 INFO 49873 --- [ main] c.a.c.s.SentinelWebAutoConfiguration : [Sentinel Starter] register SentinelWebInterceptor with urlPatterns: [/**]
② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。此时,我们可以看到 demo-provider
应用。如下图所示:
③ 使用浏览器,访问下 http://127.0.0.1:8080/demo/echo 接口 10 次。然后点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口的请求情况。如下图所示:
④ 点击 Sentinel 控制台的「簇点链路」菜单,可以看到 /demo/echo
资源。如下图所示:
⑤ 点击 /demo/echo
资源所在列的「流控」按钮,弹出「新增流控规则」。填写流控规则,如下图所示:
- 这里,我们创建的是比较简单的规则,仅允许
/demo/echo
资源被每秒调用一次。 - 更多详细的配置项的说明,胖友后续一定要认真看《Sentinel 官方文档 —— 流量控制》文章,这是 Sentinel 提供的多种规则中最最最常用的一种。
⑥ 点击「新增」按钮,完成流控规则的添加。此时,会自动跳转到「流控规则」菜单。如下图所示:
⑦ 使用浏览器,访问 http://127.0.0.1:8080/demo/echo 接口两次,会有一次被 Sentinel 流量控制而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 FlowException",
"code": 1024
}
- 流量控制对应 FlowException 异常,因此这里会看到哈。
此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:
3. 熔断降级
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
在本小节,我们来学习下 Sentinel 的流量控制功能,对应《Sentinel 官方文档 —— 熔断降级》文章。
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。
设计理念
Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过 线程池隔离 的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:
1、通过并发线程数进行限制
和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。2、通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
下面,我们来搭建一个 Sentinel 熔断降级制的使用示例。本着省时省力(努力偷懒)的原则,我们直接复用「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目。
3.1 DemoController
在 DemoController 类中,额外添加 demo/sleep
接口,通过 sleep 100 毫秒,模拟延迟较高的接口。代码如下:
@GetMapping("/sleep")
public String sleep() throws InterruptedException {
Thread.sleep(100L);
return "sleep";
}
3.2 简单测试
友情提示:在测试的过程中,咱会发现之前配置的流量控制规则不见了,不要慌,后面会详细述说。
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:8080/demo/sleep 接口,保证 /demo/sleep
资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 /demo/sleep
资源。
之后,点击 /demo/sleep
资源所在列的「降级」按钮,弹出「新增降级规则」。填写降级规则,如下图所示:Sentinel 控制台 - 新增降级规则
- 这里,我们创建的是比较简单的规则,当
/demo/sleep
资源在 5 秒的时间窗口中,如果平均响应时间超过 1 ms,则进行熔断降级。
Sentinel 一共有 3 种方式来衡量资源是否稳定:
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,则结束熔断状态后仍可能再进入熔断状态。
④ 点击「新增」按钮,完成降级规则的添加。此时,会自动跳转到「降级规则」菜单。如下图所示:
⑤ 使用浏览器,访问 http://127.0.0.1:8080/demo/sleep 接口 6 次,就会有被 Sentinel 服务降级而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 DegradeException",
"code": 1024
}
- 热点参数限流对应 DegradeException 异常,因此这里会看到哈。
此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:
耐心等待几秒,过了这个时间窗口后,继续访问 http://127.0.0.1:8080/demo/sleep 接口,又可以成功返回了。
4. 热点参数限流
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
在本小节,我们来学习下 Sentinel 的热点参数限流功能,对应《Sentinel 官方文档 —— 热点参数限流》文章。
FROM 《Sentinel 官方文档 —— 热点参数限流》
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制。
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制。
热点参数限流,会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
下面,我们来搭建一个 Sentinel 热点参数限流的使用示例。本着省时省力(努力偷懒)的原则,我们直接复用「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目。
4.1 DemoController
在 DemoController 类中,额外添加 demo/product_info
接口,用于热点参数限流的示例 API。代码如下:
@GetMapping("/product_info")
@SentinelResource("demo_product_info_hot")
public String productInfo(Integer id) {
return "商品编号:" + id;
}
- 在方法上,我们添加了
@SentinelResource
注解,自定义了demo_product_info_hot
资源。
为什么不直接使用 sentinel-spring-webmvc-adapter
库,自动给该 demo/product_info
接口生成的 /demo/product_info
资源呢?
- 原因:因为
sentinel-spring-webmvc-adapter
库提供的 SentinelWebInterceptor 拦截器在调用 Sentinel 客户端时,并未传入参数,所以无法进行热点参数限流 - 解决:使用 Sentinel 提供的
@SentinelResource
注解,自定义了demo_product_info_hot
资源。然后,通过 Spring AOP 拦截该方法的调用,实现 Sentinel 的处理逻辑。在本小节中,就是为了热点参数限流
友情提示,关于
@SentinelResource
注解,我们在「TODO. 注解支持」小节中,会专门讲解下。
4.2 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:8080/demo/product_info?id=1 接口,保证 /demo/product_info
资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 demo_product_info_hot
资源。
之后,点击 demo_product_info_hot
资源所在列的「热点」按钮,弹出「新增热点规则」。填写热点规则,如下图所示:
- 这里,我们只设置了参数索引为 0,统计窗口时长为 60 秒,请求最大次数为 10。更多设置,我们继续往下看。
④ 点击「新增」按钮,完成热点规则的添加。此时,会自动跳转到「热点规则」菜单。如下图所示:
之后,点击 demo_product_info_hot
资源所在列的「编辑」按钮,弹出「编辑热点规则」。填写热点规则,如下图所示:
- 这里,我们配置了当第一个参数的值为 1 时,限制在统计窗口中,请求最大次数为 1。
点击「 保存」按钮,完成编辑。
⑤ 使用浏览器,访问 http://127.0.0.1:8080/demo/product_info?id=1 接口 2 次,就会有被 Sentinel 热点参数限流而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 ParamFlowException",
"code": 1024
}
- 熔断降级对应 ParamFlowException 异常,因此这里会看到哈。
此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:
此时,我们访问 http://127.0.0.1:8080/demo/product_info?id=2 接口,不会存在限流的情况。而是在快速访问 10 次,才会被限流。
😈 有一点要特别注意,热点参数限流看起来和「2. 流量控制」基于 QPS 的限流是比较相似的。不过很大的差异是,热点参数限流是针对每个参数,分别计数来限流。举个例子,在当前示例的热点规则下:
- 针对每个
id
对应的 http://127.0.0.1:8080/demo/product_info?id=${id} 接口,在每 60 秒内,分别允许访问 10 次。 - 针对
id = 1
的情况,作为特殊(例外)配置,在每 60 秒内,仅仅允许访问 1 次。
详细的,胖友自己可以简单测试下,感受会非常明显哈。
5. 系统自适应限流
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
在本小节,我们来学习下 Sentinel 的系统自适应限流功能,对应《Sentinel 官方文档 —— 系统自适应限流》文章。
Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
下面,我们来搭建一个 Sentinel 系统自适应限流的使用示例。本着省时省力(努力偷懒)的原则,我们直接复用「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目。
5.1 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「系统规则」菜单,然后点击右上角「新增系统规则」按钮,弹出「新增系统保护规则」。填写降级规则,如下图所示:
- 这里,为了测试方便,我们创建了一条 CPU 超过 1% 后,自动进行系统限流。
Sentinel 一共有 5 种系统规则:
FROM 《Sentinel 官方文档 —— 系统自适应限流》
1、Load 自适应(仅对 Linux/Unix-like 机器生效)
系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的
maxQps * minRt
估算得出。设定参考值一般是CPU cores * 2.5
。2、CPU usage(1.5.0+ 版本)
当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
3、平均 RT
当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
4、并发线程数
当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
5、入口 QPS
当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
③ 使用浏览器,访问 http://127.0.0.1:8080/demo/echo 接口,直接就被 Sentinel 系统自适应限流而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 SystemBlockException",
"code": 1024
}
此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:
6. 黑白名单控制
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
在本小节,我们来学习下 Sentinel 的黑白名单控制功能,对应《Sentinel 官方文档 —— 黑白名单控制》文章。
FROM 《Sentinel 官方文档 —— 黑白名单控制》
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:
- 若配置白名单则只有请求来源位于白名单内时才可通过;
- 若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
下面,我们来搭建一个 Sentinel 黑白名单控制的使用示例。本着省时省力(努力偷懒)的原则,我们直接复用「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目。
6.1 RequestOriginParser
在 Sentinel 的子项目 sentinel-spring-webmvc-adapter
中,定义了 RequestOriginParser 接口,从请求中解析到调用来源,例如说使用 IP、请求头 user
、请求头 appName
。
因为我们要使用 Sentinel 黑白名单控制的功能,所以需要获得请求的调用来。RequestOriginParser 暂时没有提供默认的实现,所以我们自定义 CustomRequestOriginParser 实现类,解析请求头 s-user
作为调用来源。代码如下:
@Component
public class CustomRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
// <X> 从 Header 中,获得请求来源
String origin = request.getHeader("s-user");
// <Y> 如果为空,给一个默认的
if (StringUtils.isEmpty(origin)) {
origin = "default";
}
return origin;
}
}
- 在
<X>
处,我们从请求头的"s-user"
对应的值,作为请求来源。注意,Sentinel 黑白名单的控制,一般是服务和服务之间的调用。例如说,配置订单服务允许调用用户服务。 - 在
<Y>
处,我们判断未获得请求来源的时候,设置默认为default
。原因是,Sentinel 提供的 AuthorityRuleChecker 在进行黑白名单控制时,如果请求来源为空,直接就通过了 =。=
6.2 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:8080/demo/echo 接口,保证 /demo/echo
资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 /demo/echo
资源。
之后,点击 /demo/echo
资源所在列的「授权」按钮,弹出「新增授权规则」。填写授权规则,如下图所示:
- 这里,我们配置
/demo/echo
资源,仅仅允许来源为test
的请求才可以访问。
③ 点击「新增」按钮,完成授权规则的添加。此时,会自动跳转到「授权规则」菜单。如下图所示:
④ 使用浏览器,访问 http://127.0.0.1:8080/demo/echo 接口时,就会有被 Sentinel 黑白名单控制而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 AuthorityException",
"code": 1024
}
- 热点参数限流对应 AuthorityException 异常,因此这里会看到哈。
此时,点击 Sentinel 控制台的「实时监控」菜单,可以看到该接口被拒绝的统计。如下图所示:
我们来使用 Postman 来模拟一个来源为 test
的请求,如下图所示:
7. Sentinel 客户端 API
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
为了减少开发的复杂程度,Sentinel 对大部分的主流框架做了适配,例如 SpringMVC、WebFlux、Dubbo、Spring Cloud、RocketMQ 等等。我们只需要引入对应的 sentinel-apache-xxx-adapter
依赖,即可方便地整合 Sentinel。
- 在上述的示例中,我们使用的就是 Sentinel 提供的
sentinel-spring-webmvc-adapter
对 SpringMVC 的示例。 - 更多 Sentinel 的适配框架介绍,可见《Sentinel 官方文档 —— 主流框架的适配》文章。
不过,Sentinel 并不能适配所有框架,此时我们可以使用 Sentinel 客户端 API,手动进行资源的保护。在《Sentinel 官方文档 —— 如何使用》文章的定义资源和其它 API 两个小节,详细的介绍了如何使用 Sentinel 客户端 API。
下面,我们来搭建一个 Sentinel 客户端 API 的使用示例。本着省时省力(努力偷懒)的原则,我们直接复用「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目。
7.1 DemoController
在 DemoController 类中,额外添加 demo/entry_demo
接口,在内部使用 Sentinel 客户端 API 来进行资源的保护。代码如下:
@GetMapping("/entry_demo")
public String entryDemo() {
Entry entry = null;
try {
// <1> 访问资源
entry = SphU.entry("entry_demo");
// <2> ... 执行业务逻辑
return "执行成功";
} catch (BlockException ex) { // <3>
return "被拒绝";
} finally {
// <4> 释放资源
if (entry != null) {
entry.exit();
}
}
}
- 整个逻辑,和我们使用 Java 进行 I/O 操作的代码比较像,通过
try catch finally
经典套路。 <1>
处,调用 Sentinel 的SphU#entry(String name)
方法,访问资源。其中,参数name
就是在 Sentinel 中定义的资源名。如果访问资源被拒绝,例如说被限流或降级,则会抛出 BlockException 异常。<2>
处,编写具体的业务逻辑代码。<3>
处,处理访问资源被拒绝所抛出的 BlockException 异常。这里,我们是直接返回"被拒绝"
的字符串。<4>
处,调用 Sentinel 的Entry#exit()
方法,释放对资源的访问。注意,entry 和 exit 必须成对出现,不然资源一直被持有者。
这里我们编写的示例是比较简单的,推荐胖友后续自己看下 sentinel-spring-webmvc-adapter
提供的 AbstractSentinelInterceptor 拦截器对 Sentinel 客户端 API 的使用。
7.2 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:8080/demo/entry_demo 接口,保证 entry_demo
资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 entry_demo
资源。如下图所示:
之后,我们给 entry_demo
资源添加一个每秒仅允许调用一次的流控规则。如下图所示:
④ 使用浏览器,访问 http://127.0.0.1:8080/demo/echo 接口两次,会有一次被 Sentinel 流量控制而拒绝,最终返回如下 JSON 字符串:
{ "msg": "请求被拦截,拦截类型为 FlowException", "code": 1024 } |
8. 注解支持
示例代码对应仓库:
labx-04-sca-sentinel-demo01-provider
。
在「7. Sentinel 客户端 API」小节中,我们使用 Sentinel 客户端 API,手动进行资源的保护。但是我们会发现,对代码的入侵太强,需要将业务逻辑进行修改。因此,Sentinel 提供了 @SentinelResource
注解声明自定义资源,通过 Spring AOP 拦截该注解的方法,自动调用 Sentinel 客户端 API,进行指定资源的保护。
实际上,在「4. 热点参数限流」小节里,已经使用了 @SentinelResource
注解。下面,我们来看看《Sentinel 官方文档 —— 注解支持》对它的介绍:
注意:注解方式埋点不支持 private 方法。
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource
注解包含以下属性:
value
:资源名称,必需项(不能为空)entryType
:entry 类型,可选项(默认为EntryType.OUT
)blockHandler
/blockHandlerClass
:blockHandler
对应处理BlockException
的函数名称,可选项。blockHandler 函数访问范围需要是public
,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException
。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。fallback
:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
:里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback
:默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore
:用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException
时只会进入 blockHandler
处理逻辑。若未配置 blockHandler
、fallback
和 defaultFallback
,则被限流降级时会将 BlockException
直接抛出(若方法本身未定义 throws BlockException 则会被 JVM 包装一层 UndeclaredThrowableException
)。
下面,我们来搭建一个 Sentinel @SentinelResource
注解的示例。本着省时省力(努力偷懒)的原则,我们继续复用「2. 流量控制」小节的 lab-46-sentinel-demo 项目。
8.1 DemoController
在 DemoController 类中,额外添加 demo/annotations_demo
接口,使用 @SentinelResource
注解来声明资源的保护。代码如下:
@GetMapping("/annotations_demo")
@SentinelResource(value = "annotations_demo_resource",
blockHandler = "blockHandler",
fallback = "fallback")
public String annotationsDemo(@RequestParam(required = false) Integer id) throws InterruptedException {
if (id == null) {
throw new IllegalArgumentException("id 参数不允许为空");
}
return "success...";
}
// BlockHandler 处理函数,参数最后多一个 BlockException,其余与原函数一致.
public String blockHandler(Integer id, BlockException ex) {
return "block:" + ex.getClass().getSimpleName();
}
// Fallback 处理函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
public String fallback(Integer id, Throwable throwable) {
return "fallback:" + throwable.getMessage();
}
① 在方法中,如果未传 id
参数时,抛出 IllegalArgumentException 异常。
② 在方法上,添加 @SentinelResource
注解,声明资源的保护。可能比较懵逼的是,如果有 blockHandler
和 fallback
属性都配置的情况下,怎么分配异常呢?实际上,Sentinel 文档中已经提到这个情况的解答
特别地,若
blockHandler
和fallback
都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。
fallback
和blockHandler
的差异点,在于blockHandler
只能处理 BlockException 异常,fallback
能够处理所有异常。- 如果都配置的情况下,BlockException 异常分配给
blockHandler
处理,其它异常分配给fallback
处理。
8.2 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:8080/demo/annotations_demo 接口,保证 annotations_demo_resource
资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到 annotations_demo_resource
资源。如下图所示:
之后,我们给 annotations_demo_resource
资源添加一个每 60 秒的异常比例是 10% 的降级规则。如下图所示:
③ 使用浏览器,访问 http://127.0.0.1:8080/demo/annotations_demo 接口,响应结果为 "fallback:id 参数不允许为空"
。原因是,因为传入的 id
为空,所以抛出 IllegalArgumentException 异常,最终交给 #fallback(...)
方法处理。
继续不停访问 http://127.0.0.1:8080/demo/annotations_demo 接口,达到在 ② 中配置的降级规则的阀值,会响应结果为 block:DegradeException
。原因是,达到降级的阀值后,抛出的是 DegradeException 异常,而该异常是 BlockingException 的子类,所以交给 #blockHandler(...)
方法处理。
9. 规则管理及推送
友情提示:本小节内容会略微难一丢丢,请保持你耐心阅读完。然后,在跟着后续小节的示例,会更加容易理解。
在《Sentinel 官方文档 —— 在生产环境中使用 Sentinel》的「规则管理及推送」小节,详细的介绍了 Sentinel 规则的管理与推送方式的三种模式。核心内容如下:
推送模式 | 说明 | 优点 | 缺点 |
---|---|---|---|
原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource ) | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
Pull 模式 | 扩展写数据源(WritableDataSource ), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。 |
Push 模式 | 扩展读数据源(ReadableDataSource ),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。 | 规则持久化;一致性;快速 | 引入第三方依赖 |
- 详细的每个模式的说明,一定要认真认真认证看下文档,这对理解接下来的内容,非常重要哟。
9.1 原始模式
可能胖友会和艿艿一开始有相同的理解误区。Sentinel 控制台并不持久化规则,而是通过 sentinel-transport-simple-http
依赖提供的 HTTP API,将我们在 Sentinel 控制台编辑的规则,推送给集成 Sentinel 客户端的应用的内存中。如下图所示:
- 因为我们引入了
sentinel-transport-simple-http
依赖,所以应用在启动的时候,会注册到 Sentinel 控制台。因此,我们在 Sentinel 控制台的「机器列表」菜单,可以看到每个应用的示例。如下图所示: - 同时,
sentinel-transport-simple-http
依赖提供了 HTTP API 接口,提供给 Sentinel 进行规则的推送,监控的查询。具体有哪些接口,我们来一起看下,如下图所示:
这样一个梳理,是不是对原始模式的理解,稍微会清晰一些些了。另外,我们可以参考《Sentinel 官方文档 —— 如何使用》的「规则的种类」小节,直接使用代码配置规则,通过调用 FlowRuleManager#loadRules(List<FlowRule> rules)
方法,将 Sentinel 规则加载到内存当中。
9.2 Pull 和 Push 模式
对于 Pull 模式和 Push 模式,都是由 Sentinel 客户端从不同的数据源,加载配置规则。并不是所有的数据源自身支持实时推送功能,因而导致 Sentinel 的规则推送模式分成非实时的 Pull 模式,和实时的 Push 模式。
在《Sentinel 官方文档 —— 动态规则》中,将 Pull 和 Push 模式,统称为动态规则。同时,也提供了每种数据源的使用示例。😈 当然在下文中,我们会搭建在 Spring Boot 项目中的使用示例。
另外,考虑到更方便的配置 Sentinel 规则,需要将 Sentinel 控制台和配置中心等数据源进行集成。具体的,需要我们参考官方如下文档,进行自己实现。
FROM 《Sentinel 官方文档 —— 在生产环境中使用 Sentinel》
从 Sentinel 1.4.0 开始,Sentinel 控制台提供
DynamicRulePublisher
和DynamicRuleProvider
接口用于实现应用维度的规则推送和拉取,并提供了相关的示例。Sentinel 提供应用维度规则推送的示例页面(/v2/flow
),用户改造控制台对接配置中心后可直接通过 v2 页面推送规则至配置中心。改造详情可参考 应用维度规则推送示例。部署多个控制台实例时,通常需要将规则存至 DB 中,规则变更后同步向配置中心推送规则。
10. 使用 Nacos 作为数据源
示例代码对应仓库:
labx-04-sca-sentinel-nacos-provider
。
本小节,我们使用 Nacos 作为 Sentinel 规则的数据源,并使用 Push 模式推送规则。对于 Nacos 不了解的胖友,可以先看看《Nacos 极简入门》文章。
下面,我们从「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目,复制出 labx-04-sca-sentinel-nacos-provider
项目,改造成接入 Nacos 作为数据源。
10.1 引入依赖
在 pom.xml
文件中,额外引入相关依赖。
<!-- Sentinel 对 Nacos 作为数据源的支持 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
引入 sentinel-datasource-nacos
依赖,实现 Sentinel 对 Nacos 作为数据源的支持。
10.2 配置文件
修改 application.yaml
配置文件,添加 Sentinel 使用 Nacos 作为数据源。完整配置如下:
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置项,对应 SentinelProperties 配置属性类
sentinel:
enabled: true # 是否开启。默认为 true 开启
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
filter:
url-patterns: /** # 拦截请求的地址。默认为 /*
# Sentinel 规则的数据源,是一个 Map 类型。key 为数据源名,可自定义;value 为数据源的具体配置
datasource:
ds1:
# 对应 DataSourcePropertiesConfiguration 类
nacos:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
namespace: # Nacos 命名空间
group-id: DEFAULT_GROUP # Nacos 分组
data-id: ${spring.application.name}-flow-rule # Nacos 配置集编号
data-type: json # 数据格式
rule-type: FLOW # 规则类型
通过添加 spring.cloud.sentinel.datasource
配置项,设置接入的 Sentinel 规则的数据源。注意它是一个 Map 类型,其中:
① key:为数据源名,可自定义,无特殊含义。这里我们添加了一个 ds1
,如果胖友想要更多数据源,可以继续添加噢。
② value:为数据源的具体配置,对应 DataSourcePropertiesConfiguration 类,可以选择 file
、nacos
、zk
、apollo
、redis
任一作为数据的数据源。这里我们选择 nacos
来接入 Nacos 作为数据源。
rule-type
:数据源对应的 Sentinel 规则类型,在 RuleType 类枚举。这里我们设置了FLOW
对应流量控制的规则。data-type
:数据源的数据格式,默认为json
。这里我们设置了json
,所以稍后创建的 Nacos 配置集的数据格式要为JSON
。server-addr
:Nacos 服务器地址。namespace
:Nacos 分组。data-id
:Nacos 配置集编号。推荐配置集编号的命名规则为${applicationName}-${ruleType}
,因此这里我们设置为demo-provider-flow-rule
,即demo-provider
应用的流控规则。
10.3 创建 Nacos 配置集
理论来说,我们需要改造 Sentinel 控制台的代码,将 Sentinel 接入 Nacos 作为规则的数据源。但是考虑到涉及的内容较多,本文暂时跳过,感兴趣的胖友,可以阅读应用维度规则推送示例文章。
咳咳咳,理论来说,Sentinel 控制台应该内置了对 Nacos 数据源的接入。
也因此,我门直接在 Nacos 中,创建一个配置集 demo-provider-flow-rule
,具体内容如下图:
在配置内容中,我们设置了一个针对 /demo/echo
资源,每秒允许访问 5 次。每个字段的说明如下:
[
{
"resource": "/demo/echo",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- 注意是数组哈~
resource
:资源名,即限流规则的作用对象count
: 限流阈值grade
: 限流阈值类型(QPS 或并发线程数)limitApp
: 流控针对的调用来源,若为default
则不区分调用来源strategy
: 调用关系限流策略controlBehavior
: 流量控制效果(直接拒绝、Warm Up、匀速排队)
10.4 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
点击 Sentinel 控制台的「流控规则」菜单,可以看到应用中已经有一条流控规则,是从 Nacos 数据源加载而来的。如下图所示:
③ 使用浏览器,快速访问 http://127.0.0.1:8080/demo/echo 接口 6 次,最后 1 次会被 Sentinel 流量控制而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 FlowException",
"code": 1024
}
11. 使用 Apollo 作为数据源
示例代码对应仓库:
labx-04-sca-sentinel-apollo-provider
。
本小节,我们使用 Apollo 作为 Sentinel 规则的数据源,并使用 Push 模式推送规则。对于 Nacos 不了解的胖友,可以先看看《Apollo 极简入门》文章。
下面,我们从「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目,复制出 labx-04-sca-sentinel-apollo-provider
项目,改造成接入 Apollo 作为数据源。
11.1 引入依赖
在 pom.xml
文件中,额外引入相关依赖。
<!-- Sentinel 对 Apollo 作为数据源的支持 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
</dependency>
引入 sentinel-datasource-apollo
依赖,实现 Sentinel 对 Apollo 作为数据源的支持。
11.2 配置文件
修改 application.yaml
配置文件,添加 Sentinel 使用 Apollo 作为数据源。完整配置如下:
server:
port: 18080 # 服务器端口,设置为 18080 避免和本地的 Apollo 端口冲突
# Apollo 相关配置项
app:
id: ${spring.application.name} # 使用的 Apollo 的项目(应用)编号
apollo:
meta: http://127.0.0.1:8080 # Apollo Meta Server 地址
bootstrap:
enabled: true # 是否开启 Apollo 配置预加载功能。默认为 false。
eagerLoad:
enable: true # 是否开启 Apollo 支持日志级别的加载时机。默认为 false。
namespaces: application # 使用的 Apollo 的命名空间,默认为 application。
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置项,对应 SentinelProperties 配置属性类
sentinel:
enabled: true # 是否开启。默认为 true 开启
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
filter:
url-patterns: /** # 拦截请求的地址。默认为 /*
# Sentinel 规则的数据源,是一个 Map 类型。key 为数据源名,可自定义;value 为数据源的具体配置
datasource:
ds1:
# 对应 DataSourcePropertiesConfiguration 类
apollo:
namespaceName: application # Apollo 命名空间
flowRulesKey: sentinel.flow-rule # Apollo 配置 key
data-type: json # 数据格式
rule-type: FLOW # 规则类型
📚 纯 Apollo 相关配置
在 app
和 apollo
配置项,是 Apollo 相关的配置。这里我们使用 Apollo 应用为 demo-provider
。其它的配置项,胖友看注释即可,更详细的可以阅读《芋道 Spring Boot 配置中心 Apollo 入门》文章。
📚 Sentinel 数据源相关配置
通过添加 spring.cloud.sentinel.datasource
配置项,设置接入的 Sentinel 规则的数据源。注意它是一个 Map 类型,其中:
① key:为数据源名,可自定义,无特殊含义。这里我们添加了一个 ds1
,如果胖友想要更多数据源,可以继续添加噢。
② value:为数据源的具体配置,对应 DataSourcePropertiesConfiguration 类,可以选择 file
、nacos
、zk
、apollo
、redis
任一作为数据的数据源。这里我们选择 apollo
来接入 Apollo 作为数据源。
rule-type
:数据源对应的 Sentinel 规则类型,在 RuleType 类枚举。这里我们设置了FLOW
对应流量控制的规则。data-type
:数据源的数据格式,默认为json
。这里我们设置了json
,所以稍后创建的 Nacos 配置集的数据格式要为JSON
。namespaceName
:Apollo 命名空间。flowRulesKey
:Apollo 配置 Key。推荐配置项的 Key 的命名规则为sentinel.${ruleType}
,因此这里我们设置为sentinel.flow-rule
,即当前应用的流控规则。
11.4 创建 Apollo 配置
理论来说,我们需要改造 Sentinel 控制台的代码,将 Sentinel 接入 Apollo 作为规则的数据源。但是考虑到涉及的内容较多,本文暂时跳过,感兴趣的胖友,可以阅读应用维度规则推送示例文章。
咳咳咳,理论来说,Sentinel 控制台应该内置了对 Apollo 数据源的接入。
也因此,我门直接在 Apollo 中,创建一个配置项 sentinel.flow-rule
,具体内容如下图:
在配置项的 Value 中,我们设置了一个针对 /demo/echo
资源,每秒允许访问 5 次。每个字段的说明如下:
[
{
"resource": "/demo/echo",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- 注意是数组哈~
resource
:资源名,即限流规则的作用对象count
: 限流阈值grade
: 限流阈值类型(QPS 或并发线程数)limitApp
: 流控针对的调用来源,若为default
则不区分调用来源strategy
: 调用关系限流策略controlBehavior
: 流量控制效果(直接拒绝、Warm Up、匀速排队)
11.5 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
点击 Sentinel 控制台的「流控规则」菜单,可以看到应用中已经有一条流控规则,是从 Apollo 数据源加载而来的。如下图所示:
③ 使用浏览器,快速访问 http://127.0.0.1:18080/demo/echo 接口 6 次,最后 1 次会被 Sentinel 流量控制而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 FlowException",
"code": 1024
}
12. 使用 File 作为数据源
示例代码对应仓库:lab-46-sentinel-demo-file。
本小节,我们使用 File(文件) 作为 Sentinel 规则的数据源。注意,生产环境下,不建议使用 File 作为数据源。
下面,我们从「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目,复制出 labx-04-sca-sentinel-apollo-provider
项目,改造成接入 File 作为数据源。
12.1 配置文件
修改 application.yaml
配置文件,添加 Sentinel 使用 File 作为数据源。完整配置如下:
spring:
application:
name: demo-provider
cloud:
# Sentinel 配置项,对应 SentinelProperties 配置属性类
sentinel:
enabled: true # 是否开启。默认为 true 开启
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
filter:
url-patterns: /** # 拦截请求的地址。默认为 /*
# Sentinel 规则的数据源,是一个 Map 类型。key 为数据源名,可自定义;value 为数据源的具体配置
datasource:
ds1:
# 对应 DataSourcePropertiesConfiguration 类
file:
file: /Users/yunai/Sentinel/demo-provider/flow-rule.json # 配置规则所在文件。
recommendRefreshMs: 3000 # 定时读取实现刷新,默认为 3000 毫秒。
data-type: json # 数据格式
rule-type: FLOW # 规则类型
通过添加 spring.cloud.sentinel.datasource
配置项,设置接入的 Sentinel 规则的数据源。注意它是一个 Map 类型,其中:
① key:为数据源名,可自定义,无特殊含义。这里我们添加了一个 ds1
,如果胖友想要更多数据源,可以继续添加噢。
② value:为数据源的具体配置,对应 DataSourcePropertiesConfiguration 类,可以选择 file
、nacos
、zk
、apollo
、redis
任一作为数据的数据源。这里我们选择 file
来接入 Nacos 作为数据源。
rule-type
:数据源对应的 Sentinel 规则类型,在 RuleType 类枚举。这里我们设置了FLOW
对应流量控制的规则。data-type
:数据源的数据格式,默认为json
。这里我们设置了json
,所以稍后创建的 Nacos 配置集的数据格式要为JSON
。server-addr
:Nacos 服务器地址。file
:配置规则所在文件。recommendRefreshMs
:定时读取实现刷新,默认为 3000 毫秒。
12.2 创建 File 文件
创建 /Users/yunai/Sentinel/demo-provider/flow-rule.json
文件,存放应用 demo-provider
的 Sentinel 流量控制的规则。其内容如下:
[
{
"resource": "/demo/echo",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
- 注意是数组哈~
resource
:资源名,即限流规则的作用对象count
: 限流阈值grade
: 限流阈值类型(QPS 或并发线程数)limitApp
: 流控针对的调用来源,若为default
则不区分调用来源strategy
: 调用关系限流策略controlBehavior
: 流量控制效果(直接拒绝、Warm Up、匀速排队)
12.3 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
点击 Sentinel 控制台的「流控规则」菜单,可以看到应用中已经有一条流控规则,是从 File 数据源加载而来的。如下图所示:
③ 使用浏览器,快速访问 http://127.0.0.1:8080/demo/echo 接口 6 次,最后 1 次会被 Sentinel 流量控制而拒绝,最终返回如下 JSON 字符串:
{
"msg": "请求被拦截,拦截类型为 FlowException",
"code": 1024
}
旁白君:File 数据源还支持 Pull 模式推送规则的持久化,不过实际基本不会使用到。如果感兴趣的胖友,可以阅读《芋道 Spring Boot 服务容错 Sentinel 入门》文章的「12. 使用 File 作为数据源」小节。
13. 集群流控
艿艿暂时没有去研究 Sentinel 的集群流控功能,主要看 Token Server 暂时未提供高可用方案,这个上到生产肯定是有蛮大风险的。感兴趣的胖友,可以先阅读如下文章:
14. 整合 Feign
示例代码对应仓库:
本小节我们来进行 Feign 和 Sentinel 的整合,该功能由 Spring Cloud Alibaba Sentinel 的 feign
模块提供。
Feign 是一款声明式 HTTP 客户端,可以更快捷、更优雅的实现 HTTP API 调用。不了解的胖友,推荐阅读下《芋道 Spring Cloud 声明式调用 Feign 入门》文章。
下面,我们新搭建一个服务消费者项目 labx-04-sca-sentinel-feign-consumer
,并将「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目作为服务提供者,使用 Feign 进行 HTTP API 调用。最终示例项目如下图所示:
14.1 引入依赖
创建服务消费者项目 labx-04-sca-sentinel-feign-consumer
,在 pom.xml
文件中,主要引入 Sentinel 和 Feign 相关依赖。代码如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-04</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-04-sca-sentinel-feign-consumer</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Sentinel 相关依赖,使用 Sentinel 提供服务保障,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 引入 Spring Cloud OpenFeign 相关依赖,使用 OpenFeign 提供声明式调用,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
每个依赖的作用,胖友可以看艿艿在其上添加的注释。
14.2 配置文件
创建 application.yaml
配置类,添加相应配置项。配置如下:
spring:
application:
name: demo-consumer
cloud:
# Sentinel 配置项,对应 SentinelProperties 配置属性类
sentinel:
enabled: true # 是否开启。默认为 true 开启
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
filter:
url-patterns: /** # 拦截请求的地址。默认为 /*
server:
port: 8081
feign:
sentinel:
enabled: true # 开启 Sentinel 对 Feign 的支持,默认为 false 关闭。
重点是 feign.sentinel.enabled
配置项,设置为 true
,开启 Sentinel 对 Feign 的支持。
14.3 DemoProviderFeignClient
创建 DemoProviderFeignClient 接口,实现对服务 demo-provider
声明式调用。代码如下:
@FeignClient(name = "demo-provider", url = "http://127.0.0.1:8080",
fallbackFactory = DemoProviderFeignClientFallbackFactory.class)
public interface DemoProviderFeignClient {
@GetMapping("/demo/echo")
String echo();
}
通过 @FeignClient
注解,声明一个 FeignClient 客户端。
① name
属性,设置 FeignClient 客户端的名字。
② url
属性,设置调用服务的地址。因为我们没有引入注册中心,所以我们直接设置稍后启动的服务 demo-provider
的地址。
③ fallbackFactory
属性,设置 fallback 工厂类。fallback 的作用是,用于在 HTTP 调动失败而抛出异常的时候,提供 fallback 处理逻辑。
友情提示:Feign 和 Sentinel 进行整合的时候,fallback 并不是必须条件,主要看是否想要提供 fallback 处理逻辑。
14.3.1 DemoProviderFeignClientFallbackFactory
创建 DemoProviderFeignClientFallbackFactory 类,用于创建 DemoProviderFeignClientFallback 的工厂类。代码如下:
@Component
public class DemoProviderFeignClientFallbackFactory implements FallbackFactory<DemoProviderFeignClientFallback> {
@Override
public DemoProviderFeignClientFallback create(Throwable throwable) {
// 可以给 DemoProviderFeignClientFallback 提供具体的 throwable 异常
return new DemoProviderFeignClientFallback(throwable);
}
}
注意,类上需要添加 @Component
注解,因为 @FeignClient
注解的 fallbackFactory
属性,是通过从 Spring 中获取 fallbackFactory
对应类型的 Bean。
14.3.2 DemoProviderFeignClientFallback
创建 DemoProviderFeignClientFallback 类,提供 DemoProviderFeignClient 的 fallback 处理逻辑。代码如下:
public class DemoProviderFeignClientFallback implements DemoProviderFeignClient {
private Throwable throwable;
public DemoProviderFeignClientFallback(Throwable throwable) {
this.throwable = throwable;
}
@Override
public String echo() {
return "fallback:" + throwable.getClass().getSimpleName();
}
}
注意,类上需要添加 @Component
注解,因为 @FeignClient
注解的 fallbackFactory
属性,是通过从 Spring 中获取 fallbackFactory
对应类型的 Bean。
14.3.2 DemoProviderFeignClientFallback
创建 DemoProviderFeignClientFallback 类,提供 DemoProviderFeignClient 的 fallback 处理逻辑。代码如下:
public class DemoProviderFeignClientFallback implements DemoProviderFeignClient {
private Throwable throwable;
public DemoProviderFeignClientFallback(Throwable throwable) {
this.throwable = throwable;
}
@Override
public String echo() {
return "fallback:" + throwable.getClass().getSimpleName();
}
}
注意,要实现 DemoProviderFeignClient 接口,这样每个实现方法,能够一一对应,进行 fallback 处理逻辑。
14.4 ConsumerController
创建 ConsumerController 类,提供一个通过 Feign 调用服务提供者的 HTTP 接口。代码如下:
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private DemoProviderFeignClient demoProviderFeignClient;
@GetMapping("/echo")
public String echo() {
return demoProviderFeignClient.echo();
}
}
14.5 DemoConsumerApplication
创建 DemoConsumerApplication 类,创建应用启动类。代码如下:
@SpringBootApplication
@EnableFeignClients
public class DemoConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
}
}
@EnableFeignClients
注解,添加在类上,声明开启 Feign 客户端的功能。
14.6 简单测试
① 通过「2. 流量控制」小节的 DemoProviderApplication 启动服务提供者。使用 DemoConsumerApplication 启动服务消费者。
② 访问服务消费者的 http://127.0.0.1:8081/consumer/echo 接口,保证相关资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到看到 Feign 的服务提供者产生的 GET:http://127.0.0.1:8080/demo/echo
资源。如下图所示:
点击 GET:http://127.0.0.1:8080/demo/echo
资源所在列的「流控」按钮,弹出「新增流控规则」。填写流控规则,如下图所示:
- 这里,我们创建的是比较简单的规则,仅允许该资源被每秒调用一次。
④ 使用浏览器,访问 http://127.0.0.1:8081/consumer/echo 接口两次,会有一次被 Sentinel 流量控制而拒绝,返回结果为 fallback:FlowException
。这说明 Feign 和 Sentinel 的整合成功,并进入 DemoProviderFeignClient 的 fallback 处理逻辑。
15. 整合 RestTemplate
本小节我们来进行 Feign 和 RestTemplate 的整合,该功能由 Spring Cloud Alibaba Sentinel 的 custom
模块提供。
RestTemplate 是 Spring 提供的用于访问 Rest 服务的 HTTP 客户端,提供了多种可以便捷调用远程 HTTP 服务的方法,能够大大提高客户端的开发效率。
下面,我们新搭建一个服务消费者项目 labx-04-sca-sentinel-resttemplate-consumer
,并将「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目作为服务提供者,使用 Feign 进行 HTTP API 调用。最终示例项目如下图所示:项目结构
15.1 引入依赖
示例代码对应仓库:
创建服务消费者项目 labx-04-sca-sentinel-resttemplate-consumer
,在 pom.xml
文件中,主要引入 Sentinel 相关依赖。代码如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-04</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>labx-04-sca-sentinel-resttemplate-consumer</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<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>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Spring Cloud Alibaba Sentinel 相关依赖,使用 Sentinel 提供服务保障,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
每个依赖的作用,胖友可以看艿艿在其上添加的注释。
15.2 配置文件
创建 application.yaml
配置类,添加相应配置项。配置如下:
spring:
application:
name: demo-consumer
cloud:
# Sentinel 配置项,对应 SentinelProperties 配置属性类
sentinel:
enabled: true # 是否开启。默认为 true 开启
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
filter:
url-patterns: /** # 拦截请求的地址。默认为 /*
server:
port: 8081
resttemplate:
sentinel:
enabled: true # 开启 Sentinel 对 Feign 的支持,默认为 true 开启。
重点是 resttemplate.sentinel.enabled
配置项,设置为 true
,开启 Sentinel 对 RestTemplate 的支持。不过因为默认就为 true
,所以可以不配置。
15.3 RestTemplateConfiguration
创建 RestTemplateConfiguration 配置类,创建 RestTemplate Bean。代码如下:
@Configuration
public class RestTemplateConfiguration {
@Bean
@SentinelRestTemplate
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
重点! 通过 @SentinelRestTemplate
注解,声明 Sentinel 对 RestTemplate 的支持。
另外,@SentinelRestTemplate
注解提供了 blockHandler
、blockHandlerClass
、fallback
、fallbackClass
属性,作用和 @SentinelResource
注解是一致的。
15.4 ConsumerController
创建 ConsumerController 类,提供一个通过 RestTemplate 调用服务提供者的 HTTP 接口。代码如下:
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/echo")
public String echo() {
return restTemplate.getForObject("http://127.0.0.1:8080/demo/echo", String.class);
}
}
15.5 DemoConsumerApplication
创建 DemoConsumerApplication 类,创建应用启动类。代码如下:
@SpringBootApplication
public class DemoConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(DemoConsumerApplication.class, args);
}
}
15.6 简单测试
① 通过「2. 流量控制」小节的 DemoProviderApplication 启动服务提供者。使用 DemoConsumerApplication 启动服务消费者。
② 访问服务消费者的 http://127.0.0.1:8081/consumer/echo 接口,保证相关资源的初始化。
③ 使用浏览器,访问下 http://127.0.0.1:7070/ 地址,进入 Sentinel 控制台。
然后,点击 Sentinel 控制台的「簇点链路」菜单,可以看到看到 Feign 的服务提供者产生的 GET:http://127.0.0.1:8080/demo/echo
资源。如下图所示:
点击 GET:http://127.0.0.1:8080/demo/echo
资源所在列的「流控」按钮,弹出「新增流控规则」。填写流控规则,如下图所示:
- 这里,我们创建的是比较简单的规则,仅允许该资源被每秒调用一次。
④ 使用浏览器,访问 http://127.0.0.1:8081/consumer/echo 接口两次,会有一次被 Sentinel 流量控制而拒绝,返回结果为 RestTemplate request block by sentinel
。这说明 RestTemplate 和 Sentinel 的整合成功,并返回 Sentinel 对 RestTemplate 默认的 block 的响应。
16. 监控端点
示例代码对应仓库:
labx-04-sca-sentinel-actuator-provider
。
Spring Cloud Alibaba Sentinel 的 endpoint
模块,基于 Spring Boot Actuator,提供了自定义监控端点 sentinel
,获取 Sentinel 的配置项,和各种规则。
同时, Sentinel 拓展了 Spring Boot Actuator 内置的 health
端点,通过自定义的 SentinelHealthIndicator,获取和 Sentinel 控制台和数据源的连接状态。
友情提示:对 Spring Boot Actuator 不了解的胖友,可以后续阅读《芋道 Spring Boot 监控端点 Actuator 入门》文章。
下面,我们从「2. 流量控制」小节的 labx-04-sca-sentinel-demo01-provider
项目,复制出 labx-04-sca-sentinel-actuator-provider
项目,快速搭建 Sentinel 监控端点的使用示例。
16.1 引入依赖
在 pom.xml
文件中,额外引入 Spring Boot Actuator 相关依赖。代码如下:
<!-- 实现对 Actuator 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
16.2 配置文件
修改 application.yaml
配置文件,额外增加 Spring Boot Actuator 配置项。配置如下:
management:
endpoints:
web:
exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
endpoint:
# Health 端点配置项,对应 HealthProperties 配置类
health:
enabled: true # 是否开启。默认为 true 开启。
show-details: ALWAYS # 何时显示完整的健康信息。默认为 NEVER 都不展示。可选 WHEN_AUTHORIZED 当经过授权的用户;可选 ALWAYS 总是展示。
每个配置项的作用,胖友看下艿艿添加的注释。如果还不理解的话,后续看下《芋道 Spring Boot 监控端点 Actuator 入门》文章。
16.3 简单测试
① 使用 DemoProviderApplication 启动示例应用。
② 访问应用的 nacos-discovery
监控端点 http://127.0.0.1:8080/actuator/sentinel,返回结果如下图:
③ 访问应用的 health
监控端点 http://127.0.0.1:8080/actuator/health,返回结果如下图:
17. 更多的配置项信息
Spring Cloud Alibaba Sentinel 提供的配置项挺多的,我们参考文档将配置项一起梳理下。
Spring Cloud Alibaba Sentinel 提供了这些配置选项:
Sentinel 基础配置
配置项 | 说明 | 默认值 |
---|---|---|
spring.application.name or project.name | Sentinel项目名 | |
spring.cloud.sentinel.enabled | Sentinel自动化配置是否生效 | true |
spring.cloud.sentinel.eager | 是否提前触发 Sentinel 初始化 | false |
spring.cloud.sentinel.flow.cold-factor | WarmUp 模式中的 冷启动因子 | 3 |
spring.cloud.sentinel.log.dir | Sentinel 日志文件所在的目录 | |
spring.cloud.sentinel.log.switch-pid | Sentinel 日志文件名是否需要带上 pid | false |
Sentinel 控制台相关
配置项 | 说明 | 默认值 |
---|---|---|
spring.cloud.sentinel.transport.port | 应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer | 8719 |
spring.cloud.sentinel.transport.dashboard | Sentinel 控制台地址 | |
spring.cloud.sentinel.transport.heartbeat-interval-ms | 应用与Sentinel控制台的心跳间隔时间 | |
spring.cloud.sentinel.transport.client-ip | 此配置的客户端IP将被注册到 Sentinel Server 端 | |
spring.cloud.sentinel.metric.charset | metric文件字符集 | UTF-8 |
spring.cloud.sentinel.metric.file-single-size | Sentinel metric 单个文件的大小 | |
spring.cloud.sentinel.metric.file-total-count | Sentinel metric 总文件数量 |
Servlet 相关
配置项 | 说明 | 默认值 |
---|---|---|
spring.cloud.sentinel.filter.order | Servlet Filter的加载顺序。Starter内部会构造这个filter | Integer.MIN_VALUE |
spring.cloud.sentinel.filter.url-patterns | 数据类型是数组。表示Servlet Filter的url pattern集合 | /* |
spring.cloud.sentinel.filter.enabled | Enable to instance CommonFilter | true |
spring.cloud.sentinel.servlet.block-page | 自定义的跳转 URL,当请求被限流时会自动跳转至设定好的 URL |
网关 Zuul 相关
配置项 | 说明 | 默认值 |
---|---|---|
spring.cloud.sentinel.zuul.order.pre | SentinelZuulPreFilter 的 order | 10000 |
spring.cloud.sentinel.zuul.order.post | SentinelZuulPostFilter 的 order | 1000 |
spring.cloud.sentinel.zuul.order.error | SentinelZuulErrorFilter 的 order | -1 |
网关 Spring Cloud Gateway 相关
配置项 | 说明 | 默认值 |
---|---|---|
spring.cloud.sentinel.scg.fallback.mode | Spring Cloud Gateway 流控处理逻辑 (选择 redirect or response ) | |
spring.cloud.sentinel.scg.fallback.redirect | Spring Cloud Gateway 响应模式为 'redirect' 模式对应的重定向 URL | |
spring.cloud.sentinel.scg.fallback.response-body | Spring Cloud Gateway 响应模式为 'response' 模式对应的响应内容 | |
spring.cloud.sentinel.scg.fallback.response-status | Spring Cloud Gateway 响应模式为 'response' 模式对应的响应码 | 429 |
spring.cloud.sentinel.scg.fallback.content-type | Spring Cloud Gateway 响应模式为 'response' 模式对应的 content-type | application/json |
至此,我们已经完成 Spring Cloud Alibaba Sentinel 的学习。如下是 Sentinel 相关的官方文档:
更多推荐
所有评论(0)