SpringCloud Alibaba之Sentinel实现熔断与限流

(学习笔记)

QPS(Query Per Second):即每秒查询率,是对⼀个特定的查询服务器在规定时间内所处理流量多少的衡量标准。QPS = req/sec = 请求数/秒,即每秒的响应请求数,也即是最⼤吞吐能⼒。

1、介绍

(1)官网:https://sentinelguard.io/zh-cn/

(2)是什么?

主页 · alibaba/Sentinel Wiki · GitHub

(3)能干什么

丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。

完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

需要知道的相关概念:服务雪崩、服务降级、服务熔断、服务限流、服务隔离、服务超时

2、下载安装运行 

下载地址:Releases · alibaba/Sentinel · GitHub

sentinel组件由2部分构成:后台8719默认、前台8080开启 

运行命令

前提条件:Java环境,8080端口没被占用 

java -jar sentinel-dashboard-1.8.8.jar

登录账号密码均为sentinel

访问地址:http://localhost:8080

3、实操案例 

微服务8401整合Sentinel入门案例

前提:启动Nacos8848成功,启动Sentinel8080成功

3.1、新建微服务cloudalibaba-sentinel-service8401

(1)pom

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>springcloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloudalibaba-sentinel-service8401</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--SpringCloud alibaba sentinel --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!--nacos-discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version></dependency><!--SpringBoot通用依赖模块--><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><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>provided</scope></dependency><!--test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

(2)application.yml

server:port: 8401spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:discovery:server-addr: localhost:8848         #Nacos服务注册中心地址sentinel:transport:dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口

(3)主启动类

@EnableDiscoveryClient
@SpringBootApplication
public class MainSentinel8401 {public static void main(String[] args) {SpringApplication.run(MainSentinel8401.class,args);}
}

(4)业务类

@RestController
public class FlowLimitController {@GetMapping("/testA")public String testA() {return "------testA";}@GetMapping("/testB")public String testB() {return "------testB";}
}

3.2、启动8401微服务后查看sentienl控制台 

 没有数据?

Sentinel采用的懒加载说明 

注意:想使用Sentinel对某个接口进行限流和降级等操作,一定要先访问下接口,使Sentinel检测出相应的接口

执行一次访问即可 ,案例接口为:

http://localhost:8401/testA

http://localhost:8401/testB

4、流控规则

Sentinel能够对流量进行控制,主要是监控应用的QPS流量或者并发线程数等指标,如果达到指定的阈值时,就会被流量进行控制,以避免服务被瞬时的高并发流量击垮,保证服务的高可靠性。参数见最下方:

1资源名
资源的唯一名称,默认就是请求的接口路径,可以自行修改,但是要保证唯一。
2针对来源
具体针对某个微服务进行限流,默认值为default,表示不区分来源,全部限流。
3阈值类型
QPS表示通过QPS进行限流,并发线程数表示通过并发线程数限流。
4单机阈值
与阈值类型组合使用。如果阈值类型选择的是QPS,表示当调用接口的QPS达到阈值时,进行限流操作。如果阈值类型选择的是并发线程数,则表示当调用接口的并发线程数达到阈值时,进行限流操作。
5是否集群
选中则表示集群环境,不选中则表示非集群环境。

4.1、直接 

默认的流控模式,当接口达到限流条件时,直接开启限流功能。

(1)配置及说明

表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

(2)测试

快速点击访问http://localhost:8401/testA

结果:Blocked by Sentinel (flow limiting)

4.2、关联 

当关联的资源达到阈值时,就限流自己

(1)配置说明

当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名,B惹事,A挂了 

(2)测试 

Jmeter模拟并发密集访问testB

Jmeter下载地址:Apache JMeter - Download Apache JMeter

启动Jmeter

添加测试

  

4.3、链路

来自不同链路的请求对同一个目标访问时,实施针对性的不同限流措施,比如C请求来访问就限流,D请求来访问就可以

(1)修改微服务cloudalibaba-sentinel-service8401的 yaml

server:port: 8401spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:discovery:server-addr: localhost:8848         #Nacos服务注册中心地址sentinel:transport:dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路

(2)新建FlowLimitService

package com.atguigu.cloud.service;import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;@Service
public class FlowLimitService {@SentinelResource(value = "common")public void common() {System.out.println("------FlowLimitService come in");}
}

(3)修改FlowLimitController

@RestController
public class FlowLimitController {@Resourceprivate FlowLimitService flowLimitService;@GetMapping("/testA")public String testA() {return "------testA";}@GetMapping("/testB")public String testB() {return "------testB";}@GetMapping("/testC")public String testC() {flowLimitService.common();return "------testC";}@GetMapping("/testD")public String testD() {flowLimitService.common();return "------testD";}
}

(4)sentinel配置

(5) 测试

http://localhost:8401/testC,超过一秒钟一次后,就发生限流

http://localhost:8401/testD

4.4、流控效果

4.4.1、快速失败(默认的流控处理) 

直接失败,抛出异常:Blocked by Sentinel (flow limiting)

4.4.2、预热WarmUp

网址:限流 冷启动 · alibaba/Sentinel Wiki · GitHub

限流 冷启动

公式:阈值除以冷却因子coldFactor(默认值为3),经过预热时长后才会达到阈值 

官网:流量控制 · alibaba/Sentinel Wiki · GitHub 

WarmUp配置

默认 coldFactor 为 3,即请求QPS从(threshold / 3) 开始,经多少预热时长才逐渐升至设定的 QPS 阈值。
案例,单机阈值为10,预热时长设置5秒。
系统初始化的阈值为10 / 3 约等于3,即单机阈值刚开始为3(我们人工设定单机阈值是10,sentinel计算后QPS判定为3开始);
然后过了5秒后阀值才慢慢升高恢复到设置的单机阈值10,也就是说5秒钟内QPS为3,过了保护期5秒后QPS为10

应用场景:

如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。 

4.4.3、排队等待

(1)修改FlowLimitController

@GetMapping("/testE")
public String testE()
{System.out.println(System.currentTimeMillis()+"      testE,排队等待");return "------testE";
}

(2)配置

 测试:

按照单机阈值,一秒钟通过一个请求,10秒后的请求作为超时处理,放弃

4.5、阈值类型

4.5.1、QPS
4.5.2、并发线程数

(1)配置

(2)测试:Jmeter模拟多个线程并发+循环请求

5、熔断规则

官网:熔断降级 · alibaba/Sentinel Wiki · GitHub

Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛DegradeException)。

5.1、慢调用比例

5.1.1、介绍
  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。

进入熔断状态判断依据:在统计时长内,实际请求数目>设定的最小请求数    且      实际慢调用比例>比例阈值 ,进入熔断状态。 

1、熔断状态(保险丝跳闸断电,不可访问):在接下来的熔断时长内请求会自动被熔断

2、探测恢复状态(探路先锋):熔断时长结束后进入探测恢复状态

3、结束熔断(保险丝闭合恢复,可以访问):在探测恢复状态,如果接下来的一个请求响应时间小于设置的慢调用 RT,则结束熔断,否则继续熔断。

名词解释:

1.调用:一个请求发送到服务器,服务器给与响应,一个响应就是一个调用。

2.最大RT:即最大的响应时间,指系统对请求作出响应的业务处理时间, 时间单位为 ms。

3.慢调用:处理业务逻辑的实际时间>设置的最大RT时间,这个调用叫做慢调用。

4.慢调用比例:在所以调用中,慢调用占有实际的比例=慢调用次数➗总调用次数

5.比例阈值:自己设定的 , 比例阈值=慢调用次数➗调用次数

6.统计时长:时间的判断依据

7.最小请求数:设置的调用最小请求数,上图比如1秒钟打进来10个线程(大于我们配置的5个了)调用被触发

5.1.2、实操案例 

(1)微服务8401添加controller

  /*** 新增熔断规则-慢调用比例** @return*/@GetMapping("/testF")public String testF() {//暂停几秒钟线程try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("----测试:新增熔断规则-慢调用比例 ");return "------testF 新增熔断规则-慢调用比例";}

(2)sentinel配置

设置说明:1s内的请求数量大于5,且有超过10%的响应时间大于200ms,服务熔断5s后进入HALF-OPEN 状态,如果下一次请求的响应时间超过200ms,服务会再次熔断。

(3)jmeter压测

结论:

按照上述配置,熔断触发:

多次循环,一秒钟打进来10个线程(大于5个了)调用/testF,我们希望200毫秒处理完一次调用,和谐系统;^_^

假如在统计时长内,实际请求数目>最小请求数且慢调用比例>比例阈值 ,断路器打开(保险丝跳闸)微服务不可用(Blocked by Sentinel (flow limiting)),进入熔断状态5秒;后续我停止jmeter,没有这么大的访问量了,单独用浏览器访问rest地址,断路器关闭(保险丝恢复,合上闸口),

微服务恢复OK

5.2、异常比例

5.2.1、介绍
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

5.2.2、实操案例

 (1)微服务8401添加controller

    /*** 新增熔断规则-异常比例** @return*/@GetMapping("/testG")public String testG() {System.out.println("----测试:新增熔断规则-异常比例 ");int age = 10 / 0;return "------testG,新增熔断规则-异常比例 ";}

(2)配置

不配置Sentinel,对于int age=10/0,调一次错一次报错error,页面报【Whitelabel Error Page】或全局异常

配置Sentinel,对于int age=10/0,如符合如下异常比例启动熔断,页面报【Blocked by Sentinel (flow limiting)】

设置说明:1s内的请求数量大于5,且有超过20%的异常请求,服务熔断5s后进入HALF-OPEN 状态,如果下一次还是异常请求,服务会再次熔断。 

  

(3)测试

按照上述配置,单独访问一次,必然来一次报错一次(int age  = 10/0)达到100%,调一次错一次报错error

 jmeter

开启jmeter后,直接高并发发送请求 ,多次调用达到配置条件。断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务熔断+服务降级,出提示Blocked by Sentinel (flow limiting)。

测试之后还是之前的报错页面,是因为被全局异常捕捉

注释掉全局异常处理,进行测试

 

5.3、异常数 

5.3.1、介绍
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

5.3.2、实操案例 

(1)微服务8401添加controller

    /*** 新增熔断规则-异常数** @return*/@GetMapping("/testH")public String testH() {System.out.println("----测试:新增熔断规则-异常数 ");int age = 10 / 0;return "------testH,新增熔断规则-异常数 ";}

(2)配置

设置说明:1s内的请求数量大于2,且有异常请求数量大于1,服务熔断5s后进入HALF-OPEN 状态,如果下一次请求正常,熔断结束;否则继续熔断。

(3)测试

第一次请求:

jmeter 测试

6、@SentinelResource注解

概念:SentinelResource是一个流量防卫防护组件注解,用于指定防护资源,对配置的资源进行流量控制、熔断降级等功能。

注解说明:

重点(value,blockHandler,fallback)

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {//资源名称String value() default "";//entry类型,标记流量的方向,取值IN/OUT,默认是OUTEntryType entryType() default EntryType.OUT;//资源分类int resourceType() default 0;//处理BlockException的函数名称,函数要求://1. 必须是 public//2.返回类型 参数与原方法一致//3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置blockHandlerClass ,并指定blockHandlerClass里面的方法。String blockHandler() default "";//存放blockHandler的类,对应的处理函数必须static修饰。Class<?>[] blockHandlerClass() default {};//用于在抛出异常的时候提供fallback处理逻辑。 fallback函数可以针对所//有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求://1. 返回类型与原方法一致//2. 参数类型需要和原方法相匹配//3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定fallbackClass里面的方法。String fallback() default "";//存放fallback的类。对应的处理函数必须static修饰。String defaultFallback() default "";//用于通用的 fallback 逻辑。默认fallback函数可以针对所有类型的异常进//行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求://1. 返回类型与原方法一致//2. 方法参数列表为空,或者有一个 Throwable 类型的参数。//3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定 fallbackClass 里面的方法。Class<?>[] fallbackClass() default {};//需要trace的异常Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};//指定排除忽略掉哪些异常。排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。Class<? extends Throwable>[] exceptionsToIgnore() default {};
}

6.1、按照rest地址限流+默认限流返回

通过访问的rest地址来限流,会返回Sentinel自带默认的限流处理信息

(1)微服务8401添加接口RateLimitController

@RestController
public class RateLimitController {@GetMapping("/rateLimit/byUrl")public String byUrl() {return "按rest地址限流测试OK";}
}

(2)Sentinel控制台配置

(3)测试,多次连续点击 ,会返回Sentinel自带的限流处理结果,默认 

6.2、按SentinelResource​资源名称限流+自定义限流返回

不想用默认的限流提示(Blocked by Sentinel (flow limiting)),想返回自定义限流的提示。

(1)微服务8401(RateLimitController)添加接口

@GetMapping("/rateLimit/byResource")@SentinelResource(value = "byResourceSentinelResource", blockHandler = "handleException")public String byResource() {return "按资源名称SentinelResource限流测试OK";}public String handleException(BlockException exception) {return "服务不可用@SentinelResource启动" + "\t" + "o(╥﹏╥)o";}

(2)配置和代码关系

(3)测试结果

6.3、按SentinelResource​资源名称限流+自定义限流返回+服务降级处理

按照SentinelResource配置,点击超过限流配置返回自定义限流提示+程序异常返回fallback服务降级

(1)业务类RateLimitController添加代码

@GetMapping("/rateLimit/doAction/{p1}")@SentinelResource(value = "doActionSentinelResource", blockHandler = "doActionBlockHandler", fallback = "doActionFallback")public String doAction(@PathVariable("p1") Integer p1) {if (p1 == 0) {throw new RuntimeException("p1等于零直接异常");}return "doAction";}public String doActionBlockHandler(@PathVariable("p1") Integer p1, BlockException e) {log.error("sentinel配置自定义限流了:{}", e);return "sentinel配置自定义限流了";}public String doActionFallback(@PathVariable("p1") Integer p1, Throwable e) {log.error("程序逻辑异常了:{}", e);return "程序逻辑异常了" + "\t" + e.getMessage();}

(2)图形配置和代码关系

(3)测试

连续点击 http://localhost:8401/rateLimit/doAction/2,调用了 blockHandler

点击 http://localhost:8401/rateLimit/doAction/0,调用了fallback

(4)总结

blockHandler,主要针对sentinel配置后出现的违规情况处理 

fallback,程序异常了JVM抛出的异常服务降级

两者可以同时共存 

7、热点规则(热点参数限流)

官网:热点参数限流 · alibaba/Sentinel Wiki · GitHub 

热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作

7.1、实操案例 

 (1)业务类RateLimitController添加代码

   @GetMapping("/testHotKey")@SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey")public String testHotKey(@RequestParam(value = "p1", required = false) String p1,@RequestParam(value = "p2", required = false) String p2) {return "------testHotKey";}public String dealHandler_testHotKey(String p1, String p2, BlockException exception) {return "-----dealHandler_testHotKey";}

(2)配置

配置说明:方法testHotKey里面第一个参数P1只要QPS超过每秒1次,马上降级处理

(2)测试

7.2、参数例外项 

上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流。

特例情况:

普通正常限流:含有P1参数,超过1秒钟一个后,达到阈值1后马上被限流

例外特殊限流

 p1参数当它是某个特殊值时,到达某个约定值后【普通正常限流】规则突然例外、失效了,它的限流值和平时不一样

(1)添加配置

(2)测试

8、授权规则

官网:黑白名单控制 · alibaba/Sentinel Wiki · GitHub

在某些场景下,需要根据调用接口的来源判断是否允许执行本次请求。此时就可以使用Sentinel提供的授权规则来实现,Sentinel的授权规则能够根据请求的来源判断是否允许本次请求通过。 

在Sentinel的授权规则中,提供了 白名单与黑名单 两种授权类型。白放行、黑禁止 

8.1、实操案例

演示授权规则,黑名单禁止

(1)添加业务代码

@Slf4j
@RestController
public class EmpowerController //Empower授权规则,用来处理请求的来源
{@GetMapping(value = "/empower")public String requestSentinel4() {log.info("测试Sentinel授权规则empower");return "Sentinel授权规则";}
}
package com.atguigu.cloud.handler;import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;@Component
public class MyRequestOriginParser implements RequestOriginParser {@Overridepublic String parseOrigin(HttpServletRequest request) {return request.getParameter("serverName");}
}

(2)配置

(3)测试

(4)总结

上述2个rest地址,serverName=test或serverName=test2是处于黑名单的状态,无法访问,会发现无法访问,被Sentinel限流了 

9、规则持久化

问题:一旦重启微服务应用,sentinel规则将消失,生产环境需要将配置规则进行持久化

解决方法:

将限流配置规则持久化保存到Nacos,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效

9.1、案例实操

修改cloudalibaba-sentinel-service8401

(1)修改微服务8401的pom

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>springcloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloudalibaba-sentinel-service8401</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--SpringCloud ailibaba sentinel-datasource-nacos --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency><!--SpringCloud alibaba sentinel --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!--nacos-discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version></dependency><!--SpringBoot通用依赖模块--><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><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>provided</scope></dependency><!--test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

(2)修改微服务8401的yaml

server:port: 8401spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:discovery:server-addr: localhost:8848         #Nacos服务注册中心地址sentinel:transport:dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路datasource:ds1:nacos:server-addr: localhost:8848dataId: ${spring.application.name}groupId: DEFAULT_GROUPdata-type: jsonrule-type: flow # com.alibaba.cloud.sentinel.datasource.RuleType

 备注:rule-type是什么?看看源码

进一步说明:

 (3)添加Nacos业务规则配置

配置说明:请求接口:/rateLimit/byUrl,请求次数超过QPS=1,服务熔断 

[{"resource": "/rateLimit/byUrl","limitApp": "default","grade": 1,"count": 1,"strategy": 0,"controlBehavior": 0,"clusterMode": false}
]

resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。 

10、OpenFeign和Sentinel集成实现fallback服务降级

10.1、需求说明

cloudalibaba-consumer-nacos-order83   通过OpenFeign调用    cloudalibaba-provider-payment9001

 

1 83   通过OpenFeign调用  9001微服务,正常访问OK

 

2 83   通过OpenFeign调用  9001微服务,异常访问error

  访问者要有fallback服务降级的情况,不要持续访问9001加大微服务负担,但是通过feign接口调用的又方法各自不同,

  如果每个不同方法都加一个fallback配对方法,会导致代码膨胀不好管理,工程埋雷....../(ㄒoㄒ)/~~

 

 public @interface FeignClient

   通过fallback属性进行统一配置,feign接口里面定义的全部方法都走统一的服务降级,一个搞定即可

 

4 9001微服务自身还带着sentinel内部配置的流控规则,如果满足也会被触发,也即本例有2个Case

  4.1 OpenFeign接口的统一fallback服务降级处理

  4.2 Sentinel访问触发了自定义的限流配置,在注解@SentinelResource里面配置的blockHandler方法。

10.2、案例实操 

编码步骤

10.2.1、修改服务提供者cloudalibaba-provider-payment9001

(1)改pom

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>springcloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloudalibaba-provider-payment9001</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--alibaba-sentinel--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!--nacos-discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 引入自己定义的api通用包 --><dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version></dependency><!--SpringBoot通用依赖模块--><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><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>provided</scope></dependency><!--test--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

(2)写yaml

server:port: 9001spring:application:name: nacos-payment-providercloud:nacos:discovery:server-addr: localhost:8848 #配置Nacos地址sentinel:transport:dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口

(3)主启动类

@SpringBootApplication
@EnableDiscoveryClient
public class Payment9001Application {public static void main(String[] args) {SpringApplication.run(Payment9001Application.class, args);}
}

(4)业务类

@RestController
public class PayAlibabaController {@Value("${server.port}")private String serverPort;@GetMapping(value = "/pay/nacos/{id}")public String getPayInfo(@PathVariable("id") Integer id) {return "nacos registry, serverPort: " + serverPort + "\t id" + id;}//openfeign+sentinel 进行服务降级和流量控制的整合处理case@GetMapping("/pay/nacos/get/{orderNo}")@SentinelResource(value = "getPayByOrderNo", blockHandler = "handlerBlockHandler")public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo) {//模拟从数据库查询出数据并赋值给DTOPayDTO payDTO = new PayDTO();payDTO.setId(1024);payDTO.setOrderNo(orderNo);payDTO.setAmount(BigDecimal.valueOf(9.9));payDTO.setPayNo("pay:" + IdUtil.fastUUID());payDTO.setUserId(1);return ResultData.success("查询返回值:" + payDTO);}public ResultData handlerBlockHandler(@PathVariable("orderNo") String orderNo, BlockException exception) {return ResultData.fail(ReturnCodeEnum.RC500.getCode(), "getPayByOrderNo服务不可用," +"触发sentinel流控配置规则" + "\t" + "o(╥﹏╥)o");}/*注意:fallback服务降级方法纳入到Feign接口统一处理,全局一个public ResultData myFallBack(@PathVariable("orderNo") String orderNo,Throwable throwable){return ResultData.fail(ReturnCodeEnum.RC500.getCode(),"异常情况:"+throwable.getMessage());}*/
}
10.2.2、修改公共模块cloud-api-commons

 (1)改pom

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>springcloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloud-api-commons</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--alibaba-sentinel--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--web + actuator--><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>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId></dependency></dependencies></project>

(2)新增PayFeignSentinelApi接口 

package com.atguigu.cloud.apis;import com.atguigu.cloud.resp.ResultData;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(value = "nacos-payment-provider",fallback = PayFeignSentinelApiFallBack.class)
public interface PayFeignSentinelApi {@GetMapping("/pay/nacos/get/{orderNo}")ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo);
}

(3)为远程调用新建全局统一服务降级类 

fallback = PayFeignSentinelApiFallBack.class

package com.atguigu.cloud.apis;import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.resp.ReturnCodeEnum;
import org.springframework.stereotype.Component;@Component
public class PayFeignSentinelApiFallBack implements PayFeignSentinelApi {@Overridepublic ResultData getPayByOrderNo(String orderNo) {return ResultData.fail(ReturnCodeEnum.RC500.getCode(), "对方服务宕机或不可用,FallBack服务降级o(╥﹏╥)o");}
}
10.2.3、修改cloudalibaba-consumer-nacos-order83

 (1)改pom

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>springcloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloudalibaba-consumer-nacos-order83</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- 引入自己定义的api通用包 --><dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version></dependency><!--openfeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--alibaba-sentinel--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!--nacos-discovery--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--loadbalancer--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!--web + actuator--><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><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

(2)写yaml

server:port: 83spring:application:name: nacos-order-consumercloud:nacos:discovery:server-addr: localhost:8848
#消费者将要去访问的微服务名称(nacos微服务提供者叫什么你写什么)
service-url:nacos-user-service: http://nacos-payment-provider# 激活Sentinel对Feign的支持
feign:sentinel:enabled: true

(3)主启动

package com.atguigu.cloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Order83Application {public static void main(String[] args) {SpringApplication.run(Order83Application.class,args);}
}

(4)业务类

@RestController
public class OrderNacosController {@Resourceprivate RestTemplate restTemplate;@Resourceprivate PayFeignSentinelApi payFeignSentinelApi;@Value("${service-url.nacos-user-service}")private String serverURL;@GetMapping("/consumer/pay/nacos/{id}")public String paymentInfo(@PathVariable("id") Integer id) {String result = restTemplate.getForObject(serverURL + "/pay/nacos/" + id, String.class);return result + "\t" + "    我是OrderNacosController83调用者。。。。。。";}//---------------------------------------@GetMapping(value = "/consumer/pay/nacos/get/{orderNo}")public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo) {return payFeignSentinelApi.getPayByOrderNo(orderNo);}
}

(5)启动

故障现象

导致原因:

springboot+springcloud版本太高导致和阿里巴巴Sentinel不兼容 

 解决方案:总体父工程,boot+cloud降低版本

< spring.boot.version >3.2.0 </ spring.boot.version >
< spring.cloud.version >2023.0.0 </ spring.cloud.version >
上面的配置暂时为本案例注释掉,版本降级一下。
讲解完后请恢复上述高版本保持前后配置一致, 请用下面的版本替代上述
<spring.boot.version>3.0.9</spring.boot.version>
<spring.cloud.version>2022.0.2</spring.cloud.version>

10.2.4、sentinel配置

10.2.5、测试 

(1)频繁访问后触发了Sentinel的流控规则

blockHandler起效

(2) 测试83调用9001,此时故意关闭9001微服务提供者,看83消费侧自动降级,不会被耗死

11、GateWay和Sentinel集成实现服务限流

恢复父工程版本号

<spring.boot.version>3.2.0</spring.boot.version>
<spring.cloud.version>2023.0.0</spring.cloud.version>

需求说明:

cloudalibaba-sentinel-gateway9528        保护          cloudalibaba-provider-payment9001 

11.1、新建Module  cloudalibaba-sentinel-gateway9528

(1)改pom

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.atguigu.cloud</groupId><artifactId>springcloud2024</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cloudalibaba-sentinel-gateway9528</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-transport-simple-http</artifactId><version>1.8.6</version></dependency><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>1.8.6</version></dependency><dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version><scope>compile</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

(2)yaml

server:port: 9528spring:application:name: cloudalibaba-sentinel-gateway     # sentinel+gataway整合Casecloud:nacos:discovery:server-addr: localhost:8848gateway:routes:- id: pay_routh1 #pay_routh1                #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名uri: http://localhost:9001                #匹配后提供服务的路由地址predicates:- Path=/pay/**                      # 断言,路径相匹配的进行路由

(3)主启动

@SpringBootApplication
@EnableDiscoveryClient
public class Main9528 {public static void main(String[] args) {SpringApplication.run(Main9528.class, args);}
}

(4)业务类

参考官网源码:网关限流 · alibaba/Sentinel Wiki · GitHub 

Spring Cloud Gateway

从 1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
  • 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

使用时需引入以下模块(以 Maven 为例):

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>x.y.z</version>
</dependency>

使用时只需注入对应的 SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例即可(若使用了 Spring Cloud Alibaba Sentinel,则只需按照文档进行配置即可,无需自己加 Configuration)。比如:

@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {// Register the block exception handler for Spring Cloud Gateway.return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}
}

Demo 示例:sentinel-demo-spring-cloud-gateway

@Configuration
public class GatewayConfiguration {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    @PostConstruct
    public void doInit() {
        initCustomizedApis();
        initGatewayRules();
    }

    private void initCustomizedApis() {
        Set<ApiDefinition> definitions = new HashSet<>();
        ApiDefinition api1 = new ApiDefinition("some_customized_api")
            .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                add(new ApiPathPredicateItem().setPattern("/ahas"));
                add(new ApiPathPredicateItem().setPattern("/product/**")
                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
            }});
        ApiDefinition api2 = new ApiDefinition("another_customized_api")
            .setPredicateItems(new HashSet<ApiPredicateItem>() {{
                add(new ApiPathPredicateItem().setPattern("/**")
                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
            }});
        definitions.add(api1);
        definitions.add(api2);
        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
    }

    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("aliyun_route")
            .setCount(10)
            .setIntervalSec(1)
        );
        rules.add(new GatewayFlowRule("aliyun_route")
            .setCount(2)
            .setIntervalSec(2)
            .setBurst(2)
            .setParamItem(new GatewayParamFlowItem()
                .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_CLIENT_IP)
            )
        );
        rules.add(new GatewayFlowRule("httpbin_route")
            .setCount(10)
            .setIntervalSec(1)
            .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)
            .setMaxQueueingTimeoutMs(600)
            .setParamItem(new GatewayParamFlowItem()
                .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_HEADER)
                .setFieldName("X-Sentinel-Flag")
            )
        );
        rules.add(new GatewayFlowRule("httpbin_route")
            .setCount(1)
            .setIntervalSec(1)
            .setParamItem(new GatewayParamFlowItem()
                .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
                .setFieldName("pa")
            )
        );
        rules.add(new GatewayFlowRule("httpbin_route")
            .setCount(2)
            .setIntervalSec(30)
            .setParamItem(new GatewayParamFlowItem()
                .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
                .setFieldName("type")
                .setPattern("warn")
                .setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_CONTAINS)
            )
        );

        rules.add(new GatewayFlowRule("some_customized_api")
            .setResourceMode(SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME)
            .setCount(5)
            .setIntervalSec(1)
            .setParamItem(new GatewayParamFlowItem()
                .setParseStrategy(SentinelGatewayConstants.PARAM_PARSE_STRATEGY_URL_PARAM)
                .setFieldName("pn")
            )
        );
        GatewayRuleManager.loadRules(rules);
    }
}

业务代码

package com.atguigu.cloud.config;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.*;@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {// Register the block exception handler for Spring Cloud Gateway.return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}@Bean@Order(-1)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();}@PostConstructpublic void doInit() {//自定义代码initBlockHandler();}//处理+自定义返回的例外信息private void initBlockHandler() {Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("pay_routh1").setCount(2).setIntervalSec(1));GatewayRuleManager.loadRules(rules);BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map<String, String> map = new HashMap<>();map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());map.put("errorMessage", "请求太过频繁,系统忙不过来,触发限流(sentinel+gateway整合Case)");return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}}
11.2、测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1542973.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ATTCK实战系列-Vulnstack三层网络域渗透靶场(一)

ATT&CK实战系列-Vulnstack三层网络域渗透靶场&#xff08;一&#xff09; 一、环境搭建1.1 靶场拓扑图1.2 靶场下载链接1.3 虚拟机配置1.3.1 Windows 7 (web服务器)1.3.2 Windows 2008 (域控)1.3.3 Win2k3 (域内主机) 二、外网打点突破2.1 信息搜集2.2 phpmyadmin 后台 Get…

肾癌的多模态预测模型-临床-组织学-基因组

目录 摘要 技术路线 ① lncRNA的预测模型 ②病理 WSI 的分类器 ③临床病理分类器 模型结果 与别的模型比较 同行评审学习 1&#xff09;使用lncRNA的原因 2&#xff09;模型临床使用意义 3&#xff09;关于截止值的使用 摘要 A multi-classifier system integrated…

.NET常见的5种项目架构模式

前言 项目架构模式在软件开发中扮演着至关重要的角色&#xff0c;它们为开发者提供了一套组织和管理代码的指导原则&#xff0c;以提高软件的可维护性、可扩展性、可重用性和可测试性。 假如你有其他的项目架构模式推荐&#xff0c;欢迎在文末留言&#x1f91e;&#xff01;&a…

Java_Day04学习

类继承实例 package com.dx.test03; public class extendsTest {public static void main(String args[]) {// 实例化一个Cat对象&#xff0c;设置属性name和age&#xff0c;调用voice()和eat()方法&#xff0c;再打印出名字和年龄信息/********* begin *********/Cat cat ne…

实战OpenCV之直方图

基础入门 直方图是对数据分布情况的图形表示&#xff0c;特别适用于图像处理领域。在图像处理中&#xff0c;直方图通常用于表示图像中像素值的分布情况。直方图由一系列矩形条&#xff08;也被称为bin&#xff09;组成&#xff0c;每个矩形条的高度表示某个像素值&#xff08;…

鸿蒙设置,修改APP图标和名称

1、先看默认的图标和名称 2、打开项目开始设置自己需要的图标和名称 2.1找到 路径src\main\module.json5&#xff0c; 找到 abilities&#xff0c;下的&#xff0c;图标icon、名称label&#xff0c;label可以按住ctrl鼠标左键点击跳转 2.2先修改APP名称 1、ctrl鼠标左键点击…

华为OD机试 - 选修课(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

【C语言零基础入门篇 - 15】:单链表

文章目录 单链表链表的基本概念单链表功能的实现单链表的初始化单链表新结点的创建单链表头插法单链表的输出单链表的查找单链表修改单链表的删除单链表所有数据结点释放源代码 单链表 链表的基本概念 一、什么是链表&#xff1f; 链表是数据结构中线性表的一种&#xff0c;其…

华为OD机试 - 需要打开多少监控器(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

软考高级:数据库保持函数依赖和有损无损分解 AI 解读

讲解 生活化例子 想象你经营着一家快餐店&#xff0c;店里有各种商品&#xff0c;你也记录了每天的销量。你有一个表格&#xff0c;记录了「商品名称」、「价格」、「库存数量」、「供应商信息」等数据。最开始&#xff0c;你可能把所有数据都写在一张表上&#xff0c;但时间…

2024年9月22日---关于MyBatis框架(1)

一 Mybatis概述 1.1 简介 MyBatis&#xff08;官网&#xff1a;mybatis – MyBatis 3 | 简介 &#xff09;是一款优秀的开源的 持久层 框架&#xff0c;用于简化JDBC的开发。是 Apache的一个开源项目iBatis&#xff0c;2010年这个项目由apache迁移到了google code&#xff0c…

PCL 随机下采样

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#xff09; 一、概述 随机下采样 是一种常用的点…

类和对象(2)(重点)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 类的默认成员函数 概念概述 默认成员函数就是用户没有显式实现&#xff0c;编译器会自…

项目扩展一:信道池的实现

项目扩展一&#xff1a;信道池的实现 一、为何要设计信道池1.引入信道的好处2.为何要设计信道池 二、信道池的设计1.服务器需要设计信道池吗&#xff1f;2.设计&#xff1a;动态变化的信道池1.为什么&#xff1f;2.怎么办&#xff1f;1.动态扩容和缩容2.LRU风格的信道置换3.小总…

0基础学习HTML(十三)布局

HTML 布局 网页布局对改善网站的外观非常重要。 请慎重设计您的网页布局。 如何使用 <table> 元素添加布局。 网站布局 大多数网站会把内容安排到多个列中&#xff08;就像杂志或报纸那样&#xff09;。 大多数网站可以使用 <div> 或者 <table> 元素来创建…

软件测试分类篇(下)

目录 一、按照测试阶段分类 1. 单元测试 2. 集成测试 3. 系统测试 3.1 冒烟测试 3.2 回归测试 4. 验收测试 二、按照是否手工测试分类 1. 手工测试 2. 自动化测试 3. 手工测试和自动化测试的优缺点 三、按照实施组织分类 1. α测试(Alpha Testing) 2. β测试(Beta…

【LTW】Domain General Face Forgery Detection by Learning to Weight

文章目录 Domain General Face Forgery Detection by Learning to Weightkey points方法LTW元分割策略学习过程损失函数实验评价结果消融实验总结Domain General Face Forgery Detection by Learning to Weight 会议:AAAI-21 作者: code: https://github.com/skJack/LTW 上…

理解JVM中的死锁:原因及解决方案

死锁是并发应用程序中的常见问题。在此类应用程序中&#xff0c;我们使用锁定机制来确保线程安全。此外&#xff0c;我们使用线程池和信号量来管理资源消耗。然而&#xff0c;在某些情况下&#xff0c;这些技术可能会导致死锁。 在本文中&#xff0c;我们将探讨死锁、死锁出现…

旋转机械故障诊断 震动故障分析与诊断

旋转机械故障诊断 机理资料整理 电气故障&#xff0c;机械故障(不平衡&#xff0c;不对中&#xff0c;松动&#xff0c;轴承&#xff0c;共振&#xff0c;流体振动&#xff0c;皮带松动)&#xff0c;低速与高速机器故障诊断等 旋转机械故障诊断&#xff1a;机理资料整理 目录…

河钢数字PMO牛红卫受邀为第四届中国项目经理大会演讲嘉宾

全国项目经理专业人士年度盛会 河钢数字技术股份有限公司项目管理部PMO牛红卫受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾&#xff0c;演讲议题为“从技术到领导力——项目经理成长进阶之道”。大会将于10月26-27日在北京举办&…