03-13、SpringCloud Alibaba第十三章,升级篇,服务降级、熔断和限流Sentinel

[复制链接]
发表于 2025-12-13 01:39:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
SpringCloud Alibaba第十三章,升级篇,服务降级、熔断和限流Sentinel
一、Sentinel概述

1、Sentinel是什么
  1. 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
  2. 一句话概括:sentinel即Hystrix的替代品
  3. 官网: https://sentinelguard.io/zh-cn/
  4. 下载:https://github.com/alibaba/Sentinel/releases
复制代码

2、Sentinel根本概念

2.1、资源:
  1. 资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调
  2. 用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
  3. 只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,
  4. URL,甚至服务名称作为资源名来标示资源。
复制代码
2.2、规则:
  1. 围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
复制代码
2.3、流量控制:
  1. 流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度
  2. 上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能
  3. 力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状.
  4. 流量控制有一下几个角度:
  5. 1、资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  6. 2、运行指标,例如 QPS、线程池、系统负载等;
  7. 3、控制的效果,例如直接限流、冷启动、排队等。
复制代码
2.4、熔断降级:
  1. 降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳
  2. 定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
  3. Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的
  4. 时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。
  5. Sentinel和Hystrix在限制手段上,采取了不一样的方法:
  6. 1、Hystrix通过线程池的方式:
  7. Hystrix 通过线程池的方式,来对依赖进行了隔离。
  8. 2、Sentinel 对这个问题采取了两种手段:
  9. a、通过并发线程数进行限制
  10. b、通过响应时间对资源进行降级
复制代码
2.5、体系负载掩护:
  1. Sentinel 同时对系统的维度提供保护。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求
  2. 进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。
  3. 如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
  4. 针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之
  5. 内处理最多的请求。
复制代码
二、Sentinel控制台安装
  1. Sentinel分为两个部分:
  2. 1、核心库
  3. 2、控制台dashboard,基于Springboot开发,打包后可直接运行,不需要Tomcat等额外的容器
复制代码
下载:
  1. https://github.com/alibaba/Sentinel/releases
复制代码
运行:
  1. Sentinel Dashboard默认的端口是8080
  2. java -jar sentinel-dashboard-1.7.0.jar
复制代码
访问:
  1. http://localhost:8080/
  2. 账号:sentinel  密码:sentinel
复制代码
三、Sentinel案例

3.1、初始化演示工程

创建cloudalibaba-sentinel-service-8401
  1. <parent>
  2.     <artifactId>cloud_2020</artifactId>
  3.     <groupId>com.lee.springcloud</groupId>
  4.     <version>1.0-SNAPSHOT</version>
  5. </parent>
  6. <modelVersion>4.0.0</modelVersion>
  7. <artifactId>cloudalibaba-sentinel-service-8401</artifactId>
复制代码
POM
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <parent>
  6.         <artifactId>cloud_2020</artifactId>
  7.         <groupId>com.lee.springcloud</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.     </parent>
  10.     <modelVersion>4.0.0</modelVersion>
  11.     <artifactId>cloudalibaba-sentinel-service-8401</artifactId>
  12.     <dependencies>
  13.         <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
  14.         <dependency>
  15.             <groupId>com.alibaba.csp</groupId>
  16.             <artifactId>sentinel-datasource-nacos</artifactId>
  17.         </dependency>
  18.         <!--SpringCloud ailibaba sentinel -->
  19.         <dependency>
  20.             <groupId>com.alibaba.cloud</groupId>
  21.             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  22.         </dependency>
  23.         <!--SpringCloud ailibaba nacos -->
  24.         <dependency>
  25.             <groupId>com.alibaba.cloud</groupId>
  26.             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  27.         </dependency>
  28.         <dependency>
  29.             <groupId>com.lee.springcloud</groupId>
  30.             <artifactId>cloud-api-commons</artifactId>
  31.             <version>${project.version}</version>
  32.         </dependency>
  33.         <!--openfeign-->
  34.         <dependency>
  35.             <groupId>org.springframework.cloud</groupId>
  36.             <artifactId>spring-cloud-starter-openfeign</artifactId>
  37.         </dependency>
  38.         <!-- SpringBoot整合Web组件+actuator -->
  39.         <dependency>
  40.             <groupId>org.springframework.boot</groupId>
  41.             <artifactId>spring-boot-starter-web</artifactId>
  42.         </dependency>
  43.         <dependency>
  44.             <groupId>org.springframework.boot</groupId>
  45.             <artifactId>spring-boot-starter-actuator</artifactId>
  46.         </dependency>
  47.         <!--日常通用jar包配置-->
  48.         <dependency>
  49.             <groupId>org.springframework.boot</groupId>
  50.             <artifactId>spring-boot-devtools</artifactId>
  51.             <scope>runtime</scope>
  52.             <optional>true</optional>
  53.         </dependency>
  54.         <dependency>
  55.             <groupId>cn.hutool</groupId>
  56.             <artifactId>hutool-all</artifactId>
  57.             <version>4.6.3</version>
  58.         </dependency>
  59.         <dependency>
  60.             <groupId>org.projectlombok</groupId>
  61.             <artifactId>lombok</artifactId>
  62.             <optional>true</optional>
  63.         </dependency>
  64.         <dependency>
  65.             <groupId>org.springframework.boot</groupId>
  66.             <artifactId>spring-boot-starter-test</artifactId>
  67.             <scope>test</scope>
  68.         </dependency>
  69.     </dependencies>
  70. </project>
复制代码
application.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
  10.     sentinel:
  11.       transport:
  12.         dashboard: localhost:8080
  13.         port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
  14. management:
  15.   endpoints:
  16.     web:
  17.       exposure:
  18.         include: '*'
复制代码
主启动类:
  1. @SpringBootApplication
  2. @EnableDiscoveryClient
  3. public class SentinelMain8401 {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(SentinelMain8401.class,args);
  6.     }
  7. }
复制代码
业务类:
  1. @Slf4j
  2. @RestController
  3. public class FlowLimitController {
  4.     @GetMapping("/testA")
  5.     public String testA(){
  6.         return "=======>testA";
  7.     }
  8.     @GetMapping("/testB")
  9.     public String testB(){
  10.         return "=======>testB";
  11.     }
  12. }
复制代码
测试:
  1. 1、启动nacos server、Sentinel-Dashboard、CloudAlibaba-sentinel-service-8401
  2. 2、查看sentinel控制台 http://localhost:8080/
  3. 结果:空空如也
  4. (因为:Sentinel采用的是懒加载模式)
  5. 3、浏览:http://localhost:8401/testA和http://localhost:8401/testB
  6. 4、再查看sentinel控制台 http://localhost:8080/
复制代码

3.2、流控规则
  1. 资源新增流控,可以通过两个地方来添加:
  2. 1、簇点链路-点击”+流控“
  3. 2、流控规则-点击"新增流控规则"
  4. 阈值类型:
  5. QPS:系统每秒钟处理完成的请求次数
  6. (QPS是在请求进入应用之前就处理,线程数是在请求进入应用之后处理)
复制代码
3.2.1、流控模式
  1. 流控3种模式分为:直接、关联、链路
复制代码
3.2.1.1、直接


测试:
  1. 1、直接的配置如上
  2. 2、每秒访问一次http://localhost:8401/testA
  3.         正常
  4. 3、每秒多次快速的访问http://localhost:8401/testA
  5.     Blocked by Sentinel (flow limiting)
  6. (当再次恢复每秒1次的访问频率时,又可正常访问)
  7. 思考:
  8. 访问频次不符合配置规则后直接显示sentinel的默认处理Blocked by Sentinel,我们如何自定义规则不匹配的情况呢?
  9. (后续会介绍:@SentinelResource去做方法的兜底处理,类似Hystrix的@HystrixCommand)
复制代码
3.2.1.2、关联
  1. 什么是关联?即当与testA相关的资源testB达到阈值时,就挂testA
复制代码

测试:
  1. 1、配置规则如上
  2. 2、postman模拟并发密集的访问http://localhost:8401/testB
  3. 3、浏览器访问http://localhost:8401/testA
  4. 结果:Blocked by Sentinel (flow limiting)
  5. (当对testB密集访问停止后,testA访问恢复正常)
复制代码

3.2.1.3、链路

新增代码:service
  1. @Slf4j
  2. @Service
  3. public class FlowLimitService {
  4.     @SentinelResource("findOrder")
  5.     public String findOrder(){
  6.         log.info("----order----");
  7.         return "order";
  8.     }
  9. }
复制代码
controller
  1. @Slf4j
  2. @RestController
  3. public class FlowLimitController {
  4.     @Resource
  5.     private FlowLimitService flowLimitService;
  6.     @GetMapping("/testA")
  7.     public String testA(){
  8.         flowLimitService.findOrder();
  9.         return "=======>testA";
  10.     }
  11.     @GetMapping("/testB")
  12.     public String testB(){
  13.         flowLimitService.findOrder();
  14.         return "=======>testB";
  15.     }
  16. }
复制代码
设置规则:
  1. 1、配置规则如上
  2. 2、快速访问http://localhost:8401/testA
  3. 结果:
  4. ###############################有待确认#############
  5. 快速访问http://localhost:8401/testB
  6. 结果:
  7. ###############################有待确认#############
复制代码
3.2.2、流控结果

3.2.2.1、快速失败
  1. 源码:
  2. com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
  3. 上面写流控模式的时候已经展示了效果,不符合配置的时候,快速做出对应的反映,如
复制代码
3.2.2.2、Warn Up预热
  1. 源码:
  2. com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
  3. 公式:
  4. 阈值除以coldFactor(默认为3),经过预热时长后才会达到阈值
  5. 限流-冷启动:
  6. 当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲
  7. 的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启
  8. 动,预热)模式就是为了实现这个目的的。
  9. 应用场景:
  10. 秒杀系统在开启的瞬间,会有很多流量上来,会把系统打死,预热方式就是为了保护系统,可以慢慢的把流量放进来。
  11. 慢慢的把阈值增长到设定的阈值、
复制代码
  1. 配置解读:
  2. 系统初始化的阈值为10/3约等于3,即阈值刚开始为3.然后过了5秒后阈值才逐渐升到10
复制代码
3.2.2.3、列队期待
  1. 源码:
  2. com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
  3. 匀速排队,阈值必须设置为QPS。
  4. 匀速排队会严格控制请求通过的时间间隔。也即是让请求以均匀的速度通过,对应的是漏桶算法。(类似消息队列)
复制代码
  1. 配置解读:
  2. /testB每秒1次请求,超过的话就排队等待。等待的超时时间是20000ms
复制代码
3.3、降级规则
  1. 降级规则包括:RT、异常比例、异常数
复制代码
3.3.1、RT均匀相应时间
  1. RT平均响应时间:
  2. 当1s内持续进入5个请求,对应时刻的平均响应时间均超过阈值,那么在接下的时间窗口之内,对这个方法的调用都会自动地
  3. 熔断(抛出DegradeException).
  4. Sentinel的默认RT上限是4900ms,超出此阈值的都会算作4900ms。若需要变更此上线可以通过:
  5. -Dcsp.sentinel.statistic.max.rt=xxx来配置
复制代码

新增代码:
  1. @GetMapping("/testD")
  2. public String testD()
  3. {
  4.     try {
  5.         TimeUnit.SECONDS.sleep(1);
  6.     } catch (InterruptedException e) {
  7.         e.printStackTrace();
  8.     }
  9.     log.info("testD 测试RT");
  10.     return "=======>testD";
  11. }
复制代码
设置

测试:
  1. 如上JMeter创建1s中10个线程的访问去请求testD.
  2. 然后再浏览器上访问http://localhost:8401/testD
  3. 结果:
  4. Blocked by Sentinel (flow limiting)
  5. (配置中,我们希望200毫秒处理完这次任务,如果200毫秒还没处理完,在未来1s的时间窗口内,断路器打开,微服务不可用)
  6. (当我们停止JMeter测试后,没这么大访问量了,断路器关闭,微服务恢复。)
复制代码
3.3.2、非常比例
  1. 异常比例:
  2. 当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下来的时间窗口之
  3. 内,对这个方法的调用都会自动返回。
复制代码

新增代码:
  1. @GetMapping("/testE")
  2. public String testE()
  3. {
  4.     log.info("testE 测试RT");
  5.     int age = 10/0;
  6.     return "------testE";
  7. }
复制代码
设置规则:

测试:
  1. JMeter压测testE,每秒10个线程
  2. 浏览器访问:http://localhost:8401/testE
  3. 结果:不是报错,而是Blocked by Sentinel (flow limiting)
  4. 结论:
  5. 开启JMeter后,直接高并发发送请求,多次调用达到了我们的配置条件。断路器开启,微服务不可用,不再报错error而是
  6. 进入服务降级
复制代码
3.3.3、非常数
  1. 异常数:
  2. 当资源近1分钟的异常数目超过阈值之后进入熔断,这个统计时间窗口是分钟级别的,若timewindow小于60s,则结束熔断状
  3. 态后仍可能再次进入熔断状态
复制代码

新增代码:
  1. @GetMapping("/testF")
  2. public String testF()
  3. {
  4.     log.info("testF 测试异常数");
  5.     int age = 10/0;
  6.     return "------testF 测试异常数";
  7. }
复制代码
设置规则如下:
  1. 浏览器访问:http://localhost:8401/testF
  2. 前5次报错,走Error
  3. 之后报:Blocked by Sentinel (flow limiting)
  4. 61s后,服务熔断解除,走Error
复制代码
3.4、热门KEY限流

3.4.1、寻常设置
  1. 何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限
  2. 制。
复制代码
之前的case,限流出现标题后,都是Sentinel的默认提示:Blocked by Sentinel (flow limiting)
我们将使用@SentinelResource,类似Hystrix的@HystrixCommand。当方法出现标题后就找对应的兜底方法返回。
新增方法如下:
  1. @GetMapping("/testHotKey")
  2. @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
  3. public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
  4.                          @RequestParam(value = "p2",required = false) String p2) {
  5.     //int age = 10/0;
  6.     return "------testHotKey";
  7. }
  8. //兜底方法
  9. public String deal_testHotKey (String p1, String p2, BlockException exception){
  10.     return "------deal_testHotKey,o(╥﹏╥)o";
  11. }
复制代码
设置规则如下:

测试:
  1. 快速访问:http://localhost:8401/testHotKey   结果:------testHotKey
  2. 快速访问:http://localhost:8401/testHotKey?p1=abc    结果:------deal_testHotKey,o(╥﹏╥)o
  3. 快速访问:http://localhost:8401/testHotKey?p2=123  结果:------testHotKey
  4. 快速访问:http://localhost:8401/testHotKey?p1=abc&p2=123 结果:------deal_testHotKey,o(╥﹏╥)o
  5. 如果不快速访问,达不到阈值时,也只会返回------testHotKey
复制代码
3.4.2、参数例外:

我们偶然候渴望当P1参数为某个特别值时,它的限流值平静常不一样,假如当P1==5时,渴望它的阈值为200。

测试:
  1. 1、浏览器快速访问:http://localhost:8401/testHotKey?p1=5 返回:------testHotKey
  2. 2、浏览器快速访问:http://localhost:8401/testHotKey?p1=3 返回:------deal_testHotKey,o(╥﹏╥)o
  3. 注意:参数必须是基础数据类型
复制代码
3.5、体系规则
  1. 系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等
  2. 几个维度监控监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
  3. 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量
  4. (EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
  5. 系统规则支持以下的模式:
  6. 1、load自适应:仅对 Linux/Unix-like 机器生效
  7. 系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估
  8. 算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是
  9. CPU cores * 2.5。
  10. 2、CPU usage:
  11. 当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  12. 3、平均 RT:
  13. 当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  14. 4、并发线程数:
  15. 当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  16. 5、入口 QPS:
  17. 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
复制代码
3.6、@SentinelResource
  1. @SentinelResource:
  2.         类似Hystrix的@HystrixCommand,做兜底服务自定义
  3. 其中blockXXXX是处理:配置违规的
  4.         @blockHandlerClass 处理类
  5.         @blockHandler 处理类下的处理方法
  6. fallback:处理异常,做服务降级的
  7. exceptionToIgnore:忽略异常
  8. 【程序异常和违规同时发生优先执行blockHandler】
复制代码
3.6.1、按资源名称限流

新增业务类RateLimitController:
  1. @Slf4j
  2. @RestController
  3. public class RateLimitController {
  4.     @GetMapping("/byResource")
  5.     @SentinelResource(value = "byResource",blockHandler = "handleException")
  6.     public CommonResult byResource()
  7.     {
  8.         return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
  9.     }
  10.     public CommonResult handleException(BlockException exception)
  11.     {
  12.         return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
  13.     }
  14. }
复制代码
新增设置:

测试:
  1. 上述配置解析:
  2. 表示1秒钟内查询次数大于1,就限流跑到我们自定义的方法
  3. 1、1s访问一次:http://localhost:8401/byResource
  4. 结果:{"code":200,"message":"按资源名称限流测试OK","data":{"id":2020,"serial":"serial001"}}
  5. 2、1s内快速多次访问:http://localhost:8401/byResource
  6. 结果:{"code":444,"message":"com.alibaba.csp.sentinel.slots.block.flow.FlowException\t 服务不可用","data":null}
  7. 根据资源名称限流,会优先返回我们自定义的处理信息,没有自定义的返回Sentinel默认限流处理信息
复制代码
3.6.2、按URL地点限流

新增方法:
  1. @GetMapping("/rateLimit/byUrl")
  2. @SentinelResource(value = "byUrl",blockHandler = "byUrlHandler")
  3. public CommonResult byUrl()
  4. {
  5.     return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
  6. }
  7. public CommonResult byUrlHandler(BlockException exception){
  8.     return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
  9. }
复制代码
新增设置:

测试:
  1. 1、1s访问一次:http://localhost:8401/rateLimit/byUrl
  2. 结果:
  3. {"code":200,"message":"按url限流测试OK","data":{"id":2020,"serial":"serial002"}}
  4. 2、1s内快速访问:http://localhost:8401/rateLimit/byUrl
  5. 结果:
  6. Blocked by Sentinel (flow limiting)
  7. 根据url地址限流返回的是Sentinel自带的默认限流处理信息
复制代码
3.6.3、优化

以上一个方法新增一个对应的处理处罚限流方法,代码冗余且和业务稠浊,我们可以将处理处罚方法提出来做单独处理处罚
新增一个handler:
  1. public class CustomerBlockHandler {
  2.        
  3.     //注意---这里必须是static且不能为private
  4.     public static CommonResult handlerException(BlockException exception)
  5.     {
  6.         return new CommonResult(4444,"按客戶自定义,global handlerException----1");
  7.     }
  8.     public static CommonResult handlerException2(BlockException exception)
  9.     {
  10.         return new CommonResult(4444,"按客戶自定义,global handlerException----2");
  11.     }
  12. }
复制代码
业务类新增方法:
  1. @GetMapping("/rateLimit/customerBlockHandler")
  2. @SentinelResource(value = "customerBlockHandler",
  3.                   blockHandlerClass = CustomerBlockHandler.class,
  4.                   blockHandler = "handlerException")
  5. public CommonResult customerBlockHandler()
  6. {
  7.     return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
  8. }
复制代码
新增对应的设置,然后测试:
  1. 1s内多次快速的访问:http://localhost:8401/rateLimit/customerBlockHandler
  2. 结果:
  3. {"code":4444,"message":"按客戶自定义,global handlerException----1","data":null}
复制代码
3.7、Sentinel与Ribbon和Feign的整合

3.7.1、Sentinel与Ribbon

3.7.1.1、创建cloudalibaba-provider-payment-9004和9005
  1. <parent>
  2.     <artifactId>cloud_2020</artifactId>
  3.     <groupId>com.lee.springcloud</groupId>
  4.     <version>1.0-SNAPSHOT</version>
  5. </parent>
  6. <modelVersion>4.0.0</modelVersion>
  7. <artifactId>cloudalibaba-provider-payment-9004</artifactId>
复制代码
pom
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <parent>
  6.         <artifactId>cloud_2020</artifactId>
  7.         <groupId>com.lee.springcloud</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.     </parent>
  10.     <modelVersion>4.0.0</modelVersion>
  11.     <artifactId>cloudalibaba-provider-payment-9004</artifactId>
  12.     <dependencies>
  13.         <!--SpringCloud ailibaba nacos -->
  14.         <dependency>
  15.             <groupId>com.alibaba.cloud</groupId>
  16.             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  17.         </dependency>
  18.         <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
  19.             <groupId>com.lee.springcloud</groupId>
  20.             <artifactId>cloud-api-commons</artifactId>
  21.             <version>${project.version}</version>
  22.         </dependency>
  23.         <!-- SpringBoot整合Web组件 -->
  24.         <dependency>
  25.             <groupId>org.springframework.boot</groupId>
  26.             <artifactId>spring-boot-starter-web</artifactId>
  27.         </dependency>
  28.         <dependency>
  29.             <groupId>org.springframework.boot</groupId>
  30.             <artifactId>spring-boot-starter-actuator</artifactId>
  31.         </dependency>
  32.         <!--日常通用jar包配置-->
  33.         <dependency>
  34.             <groupId>org.springframework.boot</groupId>
  35.             <artifactId>spring-boot-devtools</artifactId>
  36.             <scope>runtime</scope>
  37.             <optional>true</optional>
  38.         </dependency>
  39.         <dependency>
  40.             <groupId>org.projectlombok</groupId>
  41.             <artifactId>lombok</artifactId>
  42.             <optional>true</optional>
  43.         </dependency>
  44.         <dependency>
  45.             <groupId>org.springframework.boot</groupId>
  46.             <artifactId>spring-boot-starter-test</artifactId>
  47.             <scope>test</scope>
  48.         </dependency>
  49.     </dependencies>
  50. </project>
复制代码
application.yml
  1. server:
  2.   port: 9004
  3. spring:
  4.   application:
  5.     name: nacos-payment-provider
  6.   cloud:
  7.     nacos:
  8.       discovery:
  9.         server-addr: localhost:8848 #配置Nacos地址
  10. management:
  11.   endpoints:
  12.     web:
  13.       exposure:
  14.         include: '*'
复制代码
主启动类
  1. @SpringBootApplication
  2. @EnableDiscoveryClient//服务发现
  3. public class PaymentMain9004 {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(PaymentMain9004.class,args);
  6.     }
  7. }
复制代码
业务类
  1. @Slf4j
  2. @RestController
  3. public class PaymentController {
  4.     @Value("${server.port}")
  5.     private String serverPort;
  6.     public static HashMap<Long, Payment> hashMap = new HashMap<>();
  7.     static{
  8.         hashMap.put(1L,new Payment(1L,"aaa"));
  9.         hashMap.put(2L,new Payment(2L,"bbb"));
  10.         hashMap.put(3L,new Payment(3L,"ccc"));
  11.     }
  12.     @GetMapping(value = "/paymentSQL/{id}")
  13.     public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
  14.         Payment payment = hashMap.get(id);
  15.         CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
  16.         return result;
  17.     }
  18. }
复制代码
3.7.1.2、创建cloudalibaba-consumer-order-84
  1. <parent>
  2.     <artifactId>cloud_2020</artifactId>
  3.     <groupId>com.lee.springcloud</groupId>
  4.     <version>1.0-SNAPSHOT</version>
  5. </parent>
  6. <modelVersion>4.0.0</modelVersion>
  7. <artifactId>cloudalibaba-consumer-order-84</artifactId>
复制代码
POM
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <parent>
  6.         <artifactId>cloud_2020</artifactId>
  7.         <groupId>com.lee.springcloud</groupId>
  8.         <version>1.0-SNAPSHOT</version>
  9.     </parent>
  10.     <modelVersion>4.0.0</modelVersion>
  11.     <artifactId>cloudalibaba-consumer-order-84</artifactId>
  12.     <dependencies>
  13.         <dependency>
  14.             <groupId>org.springframework.cloud</groupId>
  15.             <artifactId>spring-cloud-starter-openfeign</artifactId>
  16.         </dependency>
  17.         <dependency>
  18.             <groupId>com.alibaba.cloud</groupId>
  19.             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  20.         </dependency>
  21.         <dependency>
  22.             <groupId>com.alibaba.cloud</groupId>
  23.             <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  24.         </dependency>
  25.         <dependency>
  26.             <groupId>com.lee.springcloud</groupId>
  27.             <artifactId>cloud-api-commons</artifactId>
  28.             <version>${project.version}</version>
  29.         </dependency>
  30.         <dependency>
  31.             <groupId>org.springframework.boot</groupId>
  32.             <artifactId>spring-boot-starter-web</artifactId>
  33.         </dependency>
  34.         <dependency>
  35.             <groupId>org.springframework.boot</groupId>
  36.             <artifactId>spring-boot-starter-actuator</artifactId>
  37.         </dependency>
  38.         <dependency>
  39.             <groupId>org.springframework.boot</groupId>
  40.             <artifactId>spring-boot-devtools</artifactId>
  41.             <scope>runtime</scope>
  42.             <optional>true</optional>
  43.         </dependency>
  44.         <dependency>
  45.             <groupId>org.projectlombok</groupId>
  46.             <artifactId>lombok</artifactId>
  47.             <optional>true</optional>
  48.         </dependency>
  49.         <dependency>
  50.             <groupId>org.springframework.boot</groupId>
  51.             <artifactId>spring-boot-starter-test</artifactId>
  52.             <scope>test</scope>
  53.         </dependency>
  54.     </dependencies>
  55. </project>
复制代码
application.yml
  1. server:
  2.   port: 84
  3. spring:
  4.   application:
  5.     name: nacos-order-consumer
  6.   cloud:
  7.     nacos:
  8.       discovery:
  9.         server-addr: localhost:8848
  10.     sentinel:
  11.       transport:
  12.         dashboard: localhost:8080
  13.         port: 8719
  14. service-url:
  15.   nacos-user-service: http://nacos-payment-provider
复制代码
主启动类
  1. @EnableDiscoveryClient
  2. @SpringBootApplication
  3. @EnableFeignClients
  4. public class ConsumerOrderNacos84 {
  5.     public static void main(String[] args) {
  6.         SpringApplication.run(ConsumerOrderNacos84.class,args);
  7.     }
  8. }
复制代码
设置类
  1. @Configuration
  2. public class ApplicationContextConfig {
  3.     @Bean
  4.     @LoadBalanced
  5.     public RestTemplate  getRestTemplate()
  6.     {
  7.         return new RestTemplate();
  8.     }
  9. }
复制代码
业务类
  1. @Slf4j
  2. @RestController
  3. public class CircleBreakerController {
  4.     public static final String SERVICE_URL = "http://nacos-payment-provider";
  5.     @Resource
  6.     private RestTemplate restTemplate;
  7.     @RequestMapping("/consumer/fallback/{id}")
  8.     @SentinelResource(value = "fallback") //没有配置
  9.     //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
  10.     //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
  11.     //@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler="blockHandler",exceptionsToIgnore = {IllegalArgumentException.class})
  12.     public CommonResult<Payment> fallback(@PathVariable Long id) {
  13.         CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id, CommonResult.class,id);
  14.         if (id == 4) {
  15.             throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
  16.         }else if (result.getData() == null) {
  17.             throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
  18.         }
  19.         return result;
  20.     }
  21.     //fallback
  22.     public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
  23.         Payment payment = new Payment(id,"null");
  24.         return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
  25.     }
  26.     //blockHandler
  27.     public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
  28.         Payment payment = new Payment(id,"null");
  29.         return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
  30.     }
  31. }
复制代码
3.7.1.3、测试:
  1. 1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、
  2. cloudalibaba-consumer-order-84
  3. #############测试一############
  4. 2、浏览器访问:http://localhost:84/consumer/fallback/1
  5. 结果:
  6. {"code":200,"message":"from mysql,serverPort:  9004","data":{"id":1,"serial":"aaa"}}
  7. {"code":200,"message":"from mysql,serverPort:  9005","data":{"id":1,"serial":"aaa"}}
  8. 两个结果来回切换
  9. 3、浏览器访问:http://localhost:84/consumer/fallback/4
  10. 结果:
  11. Whitelabel Error Page
  12. #############测试二##############
  13. 4、consumer-84业务类放开注解@SentinelResource(value = "fallback",fallback = "handlerFallback")//fallback只负责业务异常
  14. 5、浏览器访问:http://localhost:84/consumer/fallback/4
  15. 结果:
  16. {"code":444,"message":"兜底异常handlerFallback,exception内容  IllegalArgumentException,非法参数异常....","data":{"id":4,"serial":"null"}}
  17. ##############测试三############
  18. 6、consumer-84业务类放开注解@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
  19. 7、且sentinel控制台新增fallback的降级策略
  20. 新增降级:
  21.         资源名:fallback 策略:异常数        异常数:2 时间窗口:2
  22. 8、浏览器访问:http://localhost:84/consumer/fallback/2
  23. 结果:正常
  24. 浏览器访问:http://localhost:84/consumer/fallback/4
  25. 结果:Whitelabel Error Page
  26. 快速多次访问:http://localhost:84/consumer/fallback/4
  27. 结果:{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException  null","data":{"id":4,"serial":"null"}}
  28. ##################测试四############
  29. 9、consumer-84业务类放开注解@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class})
  30. 10、浏览器访问:http://localhost:84/consumer/fallback/4
  31. 结果:Whitelabel Error Page
  32. 浏览器访问:http://localhost:84/consumer/fallback/5
  33. 结果:{"code":444,"message":"兜底异常handlerFallback,exception内容  NullPointerException,该ID没有对应记录,空指针异常","data":{"id":5,"serial":"null"}}
  34. 结论:
  35. @blockHandlerClass 处理类
  36. @blockHandler 处理类下的处理方法
  37. fallback:处理异常,做服务降级的
  38. exceptionToIgnore:忽略异常
复制代码
3.7.2、Sentinel与OpenFeign

修改module:cloudalibaba-consumer-order-84
POM新增(上面创建的时间就已增长过了)
  1. <dependency>
  2.     <groupId>org.springframework.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>
复制代码
yml新增:
  1. #对Feign的支持
  2. feign:
  3.   sentinel:
  4.     enabled: true
复制代码
新增feign对应的接口:paymentService
  1. @FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
  2. public interface PaymentService {
  3.     @GetMapping(value = "/paymentSQL/{id}")
  4.     public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
  5. }
复制代码
新增feign接口的对应的服务降级类:PaymentFallbackService
  1. @Component
  2. public class PaymentFallbackService implements PaymentService
  3. {
  4.     @Override
  5.     public CommonResult<Payment> paymentSQL(Long id)
  6.     {
  7.         return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
  8.     }
  9. }
复制代码
新增controller:OrderController
  1. @Slf4j
  2. @RestController
  3. public class OrderController {
  4.     // OpenFeign
  5.     @Resource
  6.     private PaymentService paymentService;
  7.     @GetMapping(value = "/consumer/feign/paymentSQL/{id}")
  8.     public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
  9.         return paymentService.paymentSQL(id);
  10.     }
  11. }
复制代码
主启动类新增注解:
  1. @EnableFeignClients
复制代码
测试:
  1. 1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、
  2. cloudalibaba-consumer-order-84
  3. 2、浏览器访问:http://localhost:84/consumer/feign/paymentSQL/5
  4. 结果:
  5. {"code":200,"message":"from mysql,serverPort:  9005","data":null}
  6. 4、此时关闭cloudalibaba-provider-payment-9004、9005两个微服务,重新访问
  7. 结果:
  8. {"code":44444,"message":"服务降级返回,---PaymentFallbackService","data":{"id":5,"serial":"errorSerial"}}
复制代码
3.8、Sentinel规则长期化

//TODO 以后再单独列出文章来写
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表