当前位置:   article > 正文

微服务之.SpringCloud AlibabaSentinel实现熔断与限流

微服务之.SpringCloud AlibabaSentinel实现熔断与限流

一、概述

1.1介绍

Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中。官方网站:

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

从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性

1.2安装

Sentinel 的使用可以分为两个部分:

  • 核心库(Jar包):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。在项目中引入依赖即可实现服务限流、隔离、熔断等功能。

  • 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。

创建文件夹

mkdir -p /docker/alibaba/sentinel/{config,data,logs}

拷贝jar包进sentinel目录下

Dockerfile文件

  1. FROM openjdk:8-jre
  2. MAINTAINER yh
  3. COPY ./sentinel-dashboard-1.8.5.jar /app.jar
  4. EXPOSE 8718
  5. ENTRYPOINT ["java", "-jar", "app.jar"]

docker-compose.yml

  1. version: '3.9'
  2. services:
  3. sentinel:
  4. build:
  5. context: ./
  6. dockerfile: ./Dockerfile
  7. image: sentinel
  8. container_name: sentinel
  9. ports:
  10. - "8718:8718"
  11. environment:
  12. JVM_OPTS: -server -Xmx512M -Xms512M -XX:MaxMetaspaceSize=256M -XX:CompressedClassSpaceSize=50M -XX:ReservedCodeCacheSize=240M -XX:MaxDirectMemorySize=400M
  13. logging:
  14. driver: "json-file"
  15. options:
  16. max-size: "10m"
  17. max-file: "1"
  18. volumes:
  19. - "/docker/alibaba/sentinel/logs:/root/logs"
  20. - "/docker/alibaba/sentinel/logs:/app-logs"
  21. command: [
  22. "--server.port=8718",
  23. "--logging.file.path=/app-logs"
  24. ]
  25. restart: always
  26. network_mode: "host"

启动

docker-compose up -d

防火墙开放8718端口

  1. firewall-cmd --permanent --add-port=8718/tcp
  2. # 防火墙重载
  3. firewall-cmd --reload

访问验证

http://172.50.2.40:8718/

登录账号密码均为sentinel
 

1.3微服务整合

我们在cart-service模块中整合sentinel,连接sentinel-dashboard控制台,步骤如下: 1)引入sentinel依赖

  1. <!--sentinel-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  5. </dependency>

2)配置控制台

修改application.yaml文件,添加下面内容:

  1. spring:
  2. cloud:
  3. sentinel:
  4. transport:
  5. dashboard: localhost:8090

3)访问cart-service的任意端点

重启cart-service,然后访问查询购物车接口,sentinel的客户端就会将服务访问的信息提交到sentinel-dashboard控制台。并展示出统计信息:

点击簇点链路菜单,会看到下面的页面:

所谓簇点链路,就是单机调用链路,是一次请求进入服务后经过的每一个被Sentinel监控的资源。默认情况下,Sentinel会监控SpringMVC的每一个Endpoint(接口)。

因此,我们看到/carts这个接口路径就是其中一个簇点,我们可以对其进行限流、熔断、隔离等保护措施。

不过,需要注意的是,我们的SpringMVC接口是按照Restful风格设计,因此购物车的查询、删除、修改等接口全部都是/carts路径:

默认情况下Sentinel会把路径作为簇点资源的名称,无法区分路径相同但请求方式不同的接口,查询、删除、修改等都被识别为一个簇点资源,这显然是不合适的。

所以我们可以选择打开Sentinel的请求方式前缀,把请求方式 + 请求路径作为簇点资源名:

首先,在cart-serviceapplication.yml中添加下面的配置:

  1. spring:
  2. cloud:
  3. sentinel:
  4. transport:
  5. dashboard: localhost:8090
  6. http-method-specify: true # 开启请求方式前缀

然后,重启服务,通过页面访问购物车的相关接口,可以看到sentinel控制台的簇点链路发生了变化:

二、基础入门

2.1流控规则

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

直接模式

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

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

关联模式

当关联的资源达到阈值时,就限流自己
当与A关联的资源B达到阀值后,就限流A自己

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

链路模式

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

  1. server:
  2. port: 8401
  3. spring:
  4. application:
  5. name: cloudalibaba-sentinel-service #8401微服务提供者后续将会被纳入阿里巴巴sentinel监管
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: localhost:8848 #Nacos服务注册中心地址
  10. sentinel:
  11. transport:
  12. dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址
  13. port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
  14. web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
  1. @Service
  2. public class FlowLimitService
  3. {
  4. @SentinelResource(value = "common")
  5. public void common()
  6. {
  7. System.out.println("------FlowLimitService come in");
  8. }
  9. }
@SentinelResource

@SentinelResource阿里巴巴开源的分布式系统的流量防卫兵Sentinel中的一个注解,用于标识资源,以便进行流量控制、熔断降级等操作。在Spring Cloud Alibaba Sentinel中,可以通过在方法上添加@SentinelResource注解来定义资源

  1. package com.yanyu.cloud.controller;
  2. import com.yanyu.cloud.service.FlowLimitService;
  3. import jakarta.annotation.Resource;
  4. import org.springframework.web.bind.annotation.GetMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6. @RestController
  7. public class FlowLimitController
  8. {
  9. @GetMapping("/testA")
  10. public String testA()
  11. {
  12. return "------testA";
  13. }
  14. @GetMapping("/testB")
  15. public String testB()
  16. {
  17. return "------testB";
  18. }
  19. /**流控-链路演示demo
  20. * C和D两个请求都访问flowLimitService.common()方法,阈值到达后对C限流,对D不管
  21. */
  22. @Resource
  23. private FlowLimitService flowLimitService;
  24. @GetMapping("/testC")
  25. public String testC()
  26. {
  27. flowLimitService.common();
  28. return "------testC";
  29. }
  30. @GetMapping("/testD")
  31. public String testD()
  32. {
  33. flowLimitService.common();
  34. return "------testD";
  35. }
  36. }

说明:C和D两个请求都访问flowLimitService.common()方法,对C限流,对D不管

2.2流控效果

直接

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

预热VarmUp

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

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

应用

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

排队等待

流控效果V2(并发线程数

配置线程隔离

接下来,点击查询商品的FeignClient对应的簇点资源后面的流控按钮:

在弹出的表单中填写下面内容:

注意,这里勾选的是并发线程数限制,也就是说这个查询功能最多使用5个线程,而不是5QPS。如果查询商品的接口每秒处理2个请求,则5个线程的实际QPS在10左右,而超出的请求自然会被拒绝。

2.3熔断规则

概述

Sentinel中的断路器不仅可以统计某个接口的慢请求比例,还可以统计异常请求比例。当这些比例超出阈值时,就会熔断该接口,即拦截访问该接口的一切请求,降级处理;当该接口恢复正常时,再放行对于该接口的请求。

断路器的工作状态切换有一个状态机来控制:

状态机包括三个状态:

  • closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态

  • open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态持续一段时间后会进入half-open状态

  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。

    • 请求成功:则切换到closed状态

    • 请求失败:则切换到open状态

我们可以在控制台通过点击簇点后的熔断按钮来配置熔断策略:

熔断策略

Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,

让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。

 

慢调用比例

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

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

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

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

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

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

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

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

异常比例

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

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

异常数

2.4@SentinelResource注解

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

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

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

测试类

  1. @RestController
  2. @Slf4j
  3. public class RateLimitController
  4. {
  5. @GetMapping("/rateLimit/byUrl")
  6. public String byUrl()
  7. {
  8. return "按rest地址限流测试OK";
  9. }
  10. }

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

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

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

  1. @GetMapping("/rateLimit/doAction/{p1}")
  2. @SentinelResource(value = "doActionSentinelResource",
  3. blockHandler = "doActionBlockHandler", fallback = "doActionFallback")
  4. public String doAction(@PathVariable("p1") Integer p1) {
  5. if (p1 == 0){
  6. throw new RuntimeException("p1等于零直接异常");
  7. }
  8. return "doAction";
  9. }
  10. public String doActionBlockHandler(@PathVariable("p1") Integer p1,BlockException e){
  11. log.error("sentinel配置自定义限流了:{}", e);
  12. return "sentinel配置自定义限流了";
  13. }
  14. public String doActionFallback(@PathVariable("p1") Integer p1,Throwable e){
  15. log.error("程序逻辑异常了:{}", e);
  16. return "程序逻辑异常了"+"\t"+e.getMessage();
  17. }

  •  blockHandler,主要针对sentinel配置后出现的违规情况处理
  • fallback,程序异常了JVM抛出的异常服务降级

2.5热点规则

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

 测试

  1. @GetMapping("/testHotKey")
  2. @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey")
  3. public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
  4. @RequestParam(value = "p2",required = false) String p2){
  5. return "------testHotKey";
  6. }
  7. public String dealHandler_testHotKey(String p1,String p2,BlockException exception)
  8. {
  9. return "-----dealHandler_testHotKey";
  10. }

参数例外项

热点参数的注意点,参数必须是基本类型或者String

2.6授权规则

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

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

  1. @RestController
  2. @Slf4j
  3. public class EmpowerController //Empower授权规则,用来处理请求的来源
  4. {
  5. @GetMapping(value = "/empower")
  6. public String requestSentinel4(){
  7. log.info("测试Sentinel授权规则empower");
  8. return "Sentinel授权规则";
  9. }
  10. }
  1. @Component
  2. public class MyRequestOriginParser implements RequestOriginParser
  3. {
  4. @Override
  5. public String parseOrigin(HttpServletRequest httpServletRequest) {
  6. return httpServletRequest.getParameter("serverName");
  7. }
  8. }

2.7持久化规则

一但。我们重启微服务应用,sentinel规则将消失,生产环境需要将配置规则进行持久化
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台
的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel_上的流控规则持续有效
 

改pom

  1. <!--SpringCloud ailibaba sentinel-datasource-nacos -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. </dependency>

改yml

  1. server:
  2. port: 8401
  3. spring:
  4. application:
  5. name: cloudalibaba-sentinel-service
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: localhost:8848 #Nacos服务注册中心地址
  10. sentinel:
  11. transport:
  12. dashboard: localhost:8090 #配置Sentinel dashboard控制台服务地址
  13. # dashboard: 114.116.205.180:8718
  14. port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
  15. web-context-unify: false # controller层的方法对service层调用不认为是同一个根链路
  16. datasource:
  17. ds1:
  18. nacos:
  19. server-addr: localhost:8848
  20. dataId: ${spring.application.name}
  21. groupId: DEFAULT_GROUP
  22. data-type: json
  23. rule-type: flow # com.alibaba.cloud.sentinel.datasource.RuleType

三、服务集成

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

问题背景

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方法。

修改服务提供方cloudalibaba-provider-payment9001

pom添加

  1. <!--openfeign-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-openfeign</artifactId>
  5. </dependency>
  6. <!--alibaba-sentinel-->
  7. <dependency>
  8. <groupId>com.alibaba.cloud</groupId>
  9. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  10. </dependency>

改yml

  1. server:
  2. port: 9001
  3. spring:
  4. application:
  5. name: nacos-payment-provider
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: localhost:8848 #配置Nacos地址
  10. sentinel:
  11. transport:
  12. dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址
  13. port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口

修改控制类

  1. package com.yanyu.cloud.controller;
  2. import cn.hutool.core.util.IdUtil;
  3. import com.alibaba.csp.sentinel.annotation.SentinelResource;
  4. import com.alibaba.csp.sentinel.slots.block.BlockException;
  5. import com.yanyu.cloud.entities.PayDTO;
  6. import com.yanyu.cloud.vo.Code;
  7. import com.yanyu.cloud.vo.ResultData;
  8. import org.springframework.beans.factory.annotation.Value;
  9. import org.springframework.web.bind.annotation.GetMapping;
  10. import org.springframework.web.bind.annotation.PathVariable;
  11. import org.springframework.web.bind.annotation.RestController;
  12. import java.math.BigDecimal;
  13. @RestController
  14. public class PayAlibabaController
  15. {
  16. @Value("${server.port}")
  17. private String serverPort;
  18. @GetMapping(value = "/pay/nacos/{id}")
  19. public String getPayInfo(@PathVariable("id") Integer id)
  20. {
  21. return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
  22. }
  23. @GetMapping("/pay/nacos/get/{orderNo}")
  24. @SentinelResource(value = "getPayByOrderNo",blockHandler = "handlerBlockHandler")
  25. public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo)
  26. {
  27. //模拟从数据库查询出数据并赋值给DTO
  28. PayDTO payDTO = new PayDTO();
  29. payDTO.setId(1024);
  30. payDTO.setOrderNo(orderNo);
  31. payDTO.setAmount(BigDecimal.valueOf(9.9));
  32. payDTO.setPayNo("pay:"+ IdUtil.fastUUID());
  33. payDTO.setUserId(1);
  34. return ResultData.success("查询返回值:"+payDTO);
  35. }
  36. public ResultData handlerBlockHandler(@PathVariable("orderNo") String orderNo, BlockException exception)
  37. {
  38. return ResultData.fail(Code.RC500.getCode(),"getPayByOrderNo服务不可用," +
  39. "触发sentinel流控配置规则"+"\t"+"o(╥﹏╥)o");
  40. }
  41. /*
  42. fallback服务降级方法纳入到Feign接口统一处理,全局一个
  43. public ResultData myFallBack(@PathVariable("orderNo") String orderNo,Throwable throwable)
  44. {
  45. return ResultData.fail(ReturnCodeEnum.RC500.getCode(),"异常情况:"+throwable.getMessage());
  46. }
  47. */
  48. }

修改c1oud-api-commons
添加pom

  1. <!--openfeign-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-openfeign</artifactId>
  5. </dependency>
  6. <!--alibaba-sentinel-->
  7. <dependency>
  8. <groupId>com.alibaba.cloud</groupId>
  9. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  10. </dependency>

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

  1. @Component
  2. public class PayFeignSentinelApiFallBack implements PayFeignApi.PayFeignSentinelApi
  3. {
  4. @Override
  5. public ResultData getPayByOrderNo(String orderNo)
  6. {
  7. return ResultData.fail(Code.RC500.getCode(),"对方服务宕机或不可用,FallBack服务降级o(╥﹏╥)o");
  8. }
  9. }

新增PayFeignSentinelApi接▣

  1. @FeignClient(value = "nacos-payment-provider",fallback = PayFeignSentinelApiFallBack.class)
  2. public interface PayFeignSentinelApi
  3. {
  4. @GetMapping("/pay/nacos/get/{orderNo}")
  5. public ResultData getPayByOrderNo(@PathVariable("orderNo") String orderNo);
  6. }

修改c1ouda1 ibaba-consumer-nacos-order83
改pom

  1. <!-- 引入自己定义的api通用包 -->
  2. <dependency>
  3. <groupId>com.atguigu.cloud</groupId>
  4. <artifactId>cloud-api-commons</artifactId>
  5. <version>1.0-SNAPSHOT</version>
  6. </dependency>
  7. <!--openfeign-->
  8. <dependency>
  9. <groupId>org.springframework.cloud</groupId>
  10. <artifactId>spring-cloud-starter-openfeign</artifactId>
  11. </dependency>
  12. <!--alibaba-sentinel-->
  13. <dependency>
  14. <groupId>com.alibaba.cloud</groupId>
  15. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  16. </dependency>

主启动类添加@EnableFeignClients)启动Feign的功能
 

3.2GateWay和Sentinel集成实现服务限流

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

pom

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.alibaba.csp</groupId>
  8. <artifactId>sentinel-transport-simple-http</artifactId>
  9. <version>1.8.6</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.alibaba.csp</groupId>
  13. <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
  14. <version>1.8.6</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>javax.annotation</groupId>
  18. <artifactId>javax.annotation-api</artifactId>
  19. <version>1.3.2</version>
  20. <scope>compile</scope>
  21. </dependency>
  22. </dependencies>

yml

  1. server:
  2. port: 9528
  3. spring:
  4. application:
  5. name: cloudalibaba-sentinel-gateway # sentinel+gataway整合Case
  6. cloud:
  7. nacos:
  8. discovery:
  9. server-addr: localhost:8848
  10. gateway:
  11. routes:
  12. - id: pay_routh1 #pay_routh1 #路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
  13. uri: http://localhost:9001 #匹配后提供服务的路由地址
  14. predicates:
  15. - Path=/pay/** # 断言,路径相匹配的进行路由

网关配置

  1. @Configuration
  2. public class GatewayConfiguration {
  3. private final List<ViewResolver> viewResolvers;
  4. private final ServerCodecConfigurer serverCodecConfigurer;
  5. public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer)
  6. {
  7. this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
  8. this.serverCodecConfigurer = serverCodecConfigurer;
  9. }
  10. @Bean
  11. @Order(Ordered.HIGHEST_PRECEDENCE)
  12. public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
  13. // Register the block exception handler for Spring Cloud Gateway.
  14. return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
  15. }
  16. @Bean
  17. @Order(-1)
  18. public GlobalFilter sentinelGatewayFilter() {
  19. return new SentinelGatewayFilter();
  20. }
  21. @PostConstruct //javax.annotation.PostConstruct
  22. public void doInit() {
  23. initBlockHandler();
  24. }
  25. //处理/自定义返回的例外信息
  26. private void initBlockHandler() {
  27. Set<GatewayFlowRule> rules = new HashSet<>();
  28. rules.add(new GatewayFlowRule("pay_routh1").setCount(2).setIntervalSec(1));
  29. GatewayRuleManager.loadRules(rules);
  30. BlockRequestHandler handler = new BlockRequestHandler() {
  31. @Override
  32. public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
  33. Map<String,String> map = new HashMap<>();
  34. map.put("errorCode", HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase());
  35. map.put("errorMessage", "请求太过频繁,系统忙不过来,触发限流(sentinel+gataway整合Case)");
  36. return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
  37. .contentType(MediaType.APPLICATION_JSON)
  38. .body(BodyInserters.fromValue(map));
  39. }
  40. };
  41. GatewayCallbackManager.setBlockHandler(handler);
  42. }
  43. }

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

闽ICP备14008679号