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

news2024/12/27 7:18:03

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

一、Sentinel概述

1、Sentinel是什么

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

一句话概括:sentinel即Hystrix的替代品

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

下载:https://github.com/alibaba/Sentinel/releases

在这里插入图片描述

2、Sentinel基本概念

2.1、资源:

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

只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,
URL,甚至服务名称作为资源名来标示资源。

2.2、规则:

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

2.3、流量控制:

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


流量控制有一下几个角度:
1、资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
2、运行指标,例如 QPS、线程池、系统负载等;
3、控制的效果,例如直接限流、冷启动、排队等。

2.4、熔断降级:

降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳
定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。

Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的
时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。




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

1、Hystrix通过线程池的方式:
Hystrix 通过线程池的方式,来对依赖进行了隔离。

2、Sentinel 对这个问题采取了两种手段:
a、通过并发线程数进行限制
b、通过响应时间对资源进行降级

2.5、系统负载保护:

Sentinel 同时对系统的维度提供保护。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求
进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。
如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。


针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之
内处理最多的请求。

二、Sentinel控制台安装

Sentinel分为两个部分:
1、核心库
2、控制台dashboard,基于Springboot开发,打包后可直接运行,不需要Tomcat等额外的容器

下载:

https://github.com/alibaba/Sentinel/releases

运行:

Sentinel Dashboard默认的端口是8080

java -jar sentinel-dashboard-1.7.0.jar

访问:

http://localhost:8080/

账号:sentinel  密码:sentinel

三、Sentinel案例

3.1、初始化演示工程

创建cloudalibaba-sentinel-service-8401

<parent>
    <artifactId>cloud_2020</artifactId>
    <groupId>com.lee.springcloud</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>cloudalibaba-sentinel-service-8401</artifactId>

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">
    <parent>
        <artifactId>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service-8401</artifactId>


    <dependencies>

        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

application.yml

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口

management:
  endpoints:
    web:
      exposure:
        include: '*'

主启动类:

@SpringBootApplication
@EnableDiscoveryClient
public class SentinelMain8401 {

    public static void main(String[] args) {
        SpringApplication.run(SentinelMain8401.class,args);
    }
}

业务类:

@Slf4j
@RestController
public class FlowLimitController {

    @GetMapping("/testA")
    public String testA(){
        return "=======>testA";
    }

    @GetMapping("/testB")
    public String testB(){
        return "=======>testB";
    }
}

测试:

1、启动nacos server、Sentinel-Dashboard、CloudAlibaba-sentinel-service-8401
2、查看sentinel控制台 http://localhost:8080/

结果:空空如也
(因为:Sentinel采用的是懒加载模式)
3、浏览:http://localhost:8401/testA和http://localhost:8401/testB
4、再查看sentinel控制台 http://localhost:8080/

在这里插入图片描述

3.2、流控规则

资源新增流控,可以通过两个地方来添加:
1、簇点链路-点击”+流控“
2、流控规则-点击"新增流控规则"


阈值类型:
QPS:系统每秒钟处理完成的请求次数

(QPS是在请求进入应用之前就处理,线程数是在请求进入应用之后处理)

3.2.1、流控模式

流控3种模式分为:直接、关联、链路
3.2.1.1、直接

在这里插入图片描述

测试:

1、直接的配置如上
2、每秒访问一次http://localhost:8401/testA
	正常
3、每秒多次快速的访问http://localhost:8401/testA
    Blocked by Sentinel (flow limiting)
(当再次恢复每秒1次的访问频率时,又可正常访问)


思考:
访问频次不符合配置规则后直接显示sentinel的默认处理Blocked by Sentinel,我们如何自定义规则不匹配的情况呢?
(后续会介绍:@SentinelResource去做方法的兜底处理,类似Hystrix的@HystrixCommand)
3.2.1.2、关联
什么是关联?即当与testA相关的资源testB达到阈值时,就挂testA

在这里插入图片描述

测试:

1、配置规则如上
2、postman模拟并发密集的访问http://localhost:8401/testB
3、浏览器访问http://localhost:8401/testA

结果:Blocked by Sentinel (flow limiting)

(当对testB密集访问停止后,testA访问恢复正常)

在这里插入图片描述

3.2.1.3、链路

新增代码:service

@Slf4j
@Service
public class FlowLimitService {

    @SentinelResource("findOrder")
    public String findOrder(){
        log.info("----order----");
        return "order";
    }
}

controller

@Slf4j
@RestController
public class FlowLimitController {

    @Resource
    private FlowLimitService flowLimitService;

    @GetMapping("/testA")
    public String testA(){
        flowLimitService.findOrder();
        return "=======>testA";
    }

    @GetMapping("/testB")
    public String testB(){
        flowLimitService.findOrder();
        return "=======>testB";
    }
}

配置规则:

在这里插入图片描述

1、配置规则如上
2、快速访问http://localhost:8401/testA
结果:
###############################有待确认#############
快速访问http://localhost:8401/testB
结果:
###############################有待确认#############

3.2.2、流控效果

3.2.2.1、快速失败
源码:
com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

上面写流控模式的时候已经展示了效果,不符合配置的时候,快速做出对应的反映,如
3.2.2.2、Warn Up预热
源码:
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

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


限流-冷启动:
当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲
的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启
动,预热)模式就是为了实现这个目的的。


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

在这里插入图片描述

配置解读:
系统初始化的阈值为10/3约等于3,即阈值刚开始为3.然后过了5秒后阈值才逐渐升到10
3.2.2.3、排队等待
源码:
com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

匀速排队,阈值必须设置为QPS。

匀速排队会严格控制请求通过的时间间隔。也即是让请求以均匀的速度通过,对应的是漏桶算法。(类似消息队列)

在这里插入图片描述

配置解读:
/testB每秒1次请求,超过的话就排队等待。等待的超时时间是20000ms

3.3、降级规则

降级规则包括:RT、异常比例、异常数
3.3.1、RT平均响应时间
RT平均响应时间:
当1s内持续进入5个请求,对应时刻的平均响应时间均超过阈值,那么在接下的时间窗口之内,对这个方法的调用都会自动地
熔断(抛出DegradeException).

Sentinel的默认RT上限是4900ms,超出此阈值的都会算作4900ms。若需要变更此上线可以通过:
-Dcsp.sentinel.statistic.max.rt=xxx来配置

在这里插入图片描述

新增代码:

@GetMapping("/testD")
public String testD()
{
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("testD 测试RT");
    return "=======>testD";
}

配置

在这里插入图片描述

测试:

在这里插入图片描述

如上JMeter创建1s中10个线程的访问去请求testD.

然后再浏览器上访问http://localhost:8401/testD
结果:
Blocked by Sentinel (flow limiting)

(配置中,我们希望200毫秒处理完这次任务,如果200毫秒还没处理完,在未来1s的时间窗口内,断路器打开,微服务不可用)

(当我们停止JMeter测试后,没这么大访问量了,断路器关闭,微服务恢复。)
3.3.2、异常比例
异常比例:
当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下来的时间窗口之
内,对这个方法的调用都会自动返回。

在这里插入图片描述

新增代码:

@GetMapping("/testE")
public String testE()
{
    log.info("testE 测试RT");
    int age = 10/0;
    return "------testE";
}

配置规则:

在这里插入图片描述

测试:

JMeter压测testE,每秒10个线程

浏览器访问:http://localhost:8401/testE

结果:不是报错,而是Blocked by Sentinel (flow limiting)

结论:
开启JMeter后,直接高并发发送请求,多次调用达到了我们的配置条件。断路器开启,微服务不可用,不再报错error而是
进入服务降级
3.3.3、异常数
异常数:
当资源近1分钟的异常数目超过阈值之后进入熔断,这个统计时间窗口是分钟级别的,若timewindow小于60s,则结束熔断状
态后仍可能再次进入熔断状态

在这里插入图片描述

新增代码:

@GetMapping("/testF")
public String testF()
{
    log.info("testF 测试异常数");
    int age = 10/0;
    return "------testF 测试异常数";
}

配置规则如下:

在这里插入图片描述

浏览器访问:http://localhost:8401/testF
前5次报错,走Error
之后报:Blocked by Sentinel (flow limiting)
61s后,服务熔断解除,走Error

3.4、热点KEY限流

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

之前的case,限流出现问题后,都是Sentinel的默认提示:Blocked by Sentinel (flow limiting)

我们将使用@SentinelResource,类似Hystrix的@HystrixCommand。当方法出现问题后就找对应的兜底方法返回。

新增方法如下:

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                         @RequestParam(value = "p2",required = false) String p2) {
    //int age = 10/0;
    return "------testHotKey";
}

//兜底方法
public String deal_testHotKey (String p1, String p2, BlockException exception){
    return "------deal_testHotKey,o(╥﹏╥)o";
}

配置规则如下:

在这里插入图片描述

测试:

快速访问:http://localhost:8401/testHotKey   结果:------testHotKey

快速访问:http://localhost:8401/testHotKey?p1=abc    结果:------deal_testHotKey,o(╥﹏╥)o

快速访问:http://localhost:8401/testHotKey?p2=123  结果:------testHotKey

快速访问:http://localhost:8401/testHotKey?p1=abc&p2=123 结果:------deal_testHotKey,o(╥﹏╥)o

如果不快速访问,达不到阈值时,也只会返回------testHotKey

3.4.2、参数例外:

我们有时候期望当P1参数为某个特殊值时,它的限流值和平时不一样,假如当P1==5时,期望它的阈值为200。

在这里插入图片描述

测试:

1、浏览器快速访问:http://localhost:8401/testHotKey?p1=5 返回:------testHotKey

2、浏览器快速访问:http://localhost:8401/testHotKey?p1=3 返回:------deal_testHotKey,o(╥﹏╥)o

注意:参数必须是基础数据类型

3.5、系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等
几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量
(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的模式:
1、load自适应:仅对 Linux/Unix-like 机器生效
系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估
算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 
CPU cores * 2.5。


2、CPU usage:
当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。

3、平均 RT:
当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。

4、并发线程数:
当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。

5、入口 QPS:
当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

3.6、@SentinelResource

@SentinelResource:
	类似Hystrix的@HystrixCommand,做兜底服务自定义

其中blockXXXX是处理:配置违规的
	@blockHandlerClass 处理类
	@blockHandler 处理类下的处理方法

fallback:处理异常,做服务降级的
exceptionToIgnore:忽略异常

【程序异常和违规同时发生优先执行blockHandler】
3.6.1、按资源名称限流

新增业务类RateLimitController:

@Slf4j
@RestController
public class RateLimitController {

    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource()
    {
        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }
    public CommonResult handleException(BlockException exception)
    {
        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }

}

新增配置:

在这里插入图片描述

测试:

上述配置解析:
表示1秒钟内查询次数大于1,就限流跑到我们自定义的方法

1、1s访问一次:http://localhost:8401/byResource
结果:{"code":200,"message":"按资源名称限流测试OK","data":{"id":2020,"serial":"serial001"}}

2、1s内快速多次访问:http://localhost:8401/byResource
结果:{"code":444,"message":"com.alibaba.csp.sentinel.slots.block.flow.FlowException\t 服务不可用","data":null}

根据资源名称限流,会优先返回我们自定义的处理信息,没有自定义的返回Sentinel默认限流处理信息
3.6.2、按URL地址限流

新增方法:

@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl",blockHandler = "byUrlHandler")
public CommonResult byUrl()
{
    return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
}

public CommonResult byUrlHandler(BlockException exception){
    return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
}

新增配置:

在这里插入图片描述

测试:

1、1s访问一次:http://localhost:8401/rateLimit/byUrl
结果:
{"code":200,"message":"按url限流测试OK","data":{"id":2020,"serial":"serial002"}}

2、1s内快速访问:http://localhost:8401/rateLimit/byUrl
结果:
Blocked by Sentinel (flow limiting)

根据url地址限流返回的是Sentinel自带的默认限流处理信息
3.6.3、优化

以上一个方法新增一个对应的处理限流方法,代码冗余且和业务混杂,我们可以将处理方法提出来做单独处理

新增一个handler:

public class CustomerBlockHandler {
	
    //注意---这里必须是static且不能为private
    public static CommonResult handlerException(BlockException exception)
    {
        return new CommonResult(4444,"按客戶自定义,global handlerException----1");
    }
    public static CommonResult handlerException2(BlockException exception)
    {
        return new CommonResult(4444,"按客戶自定义,global handlerException----2");
    }

}

业务类新增方法:

@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
                  blockHandlerClass = CustomerBlockHandler.class,
                  blockHandler = "handlerException")
public CommonResult customerBlockHandler()
{
    return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}

新增对应的配置,然后测试:

1s内多次快速的访问:http://localhost:8401/rateLimit/customerBlockHandler

结果:
{"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
<parent>
    <artifactId>cloud_2020</artifactId>
    <groupId>com.lee.springcloud</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-provider-payment-9004</artifactId>

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">
    <parent>
        <artifactId>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloudalibaba-provider-payment-9004</artifactId>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

application.yml

server:
  port: 9004

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

主启动类

@SpringBootApplication
@EnableDiscoveryClient//服务发现
public class PaymentMain9004 {

    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9004.class,args);
    }
}

业务类

@Slf4j
@RestController
public class PaymentController {

    @Value("${server.port}")
    private String serverPort;

    public static HashMap<Long, Payment> hashMap = new HashMap<>();
    static{
        hashMap.put(1L,new Payment(1L,"aaa"));
        hashMap.put(2L,new Payment(2L,"bbb"));
        hashMap.put(3L,new Payment(3L,"ccc"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
        Payment payment = hashMap.get(id);
        CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }

}
3.7.1.2、创建cloudalibaba-consumer-order-84
<parent>
    <artifactId>cloud_2020</artifactId>
    <groupId>com.lee.springcloud</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloudalibaba-consumer-order-84</artifactId>

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">
    <parent>
        <artifactId>cloud_2020</artifactId>
        <groupId>com.lee.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloudalibaba-consumer-order-84</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.lee.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <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.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

application.yml

server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719

service-url:
  nacos-user-service: http://nacos-payment-provider

主启动类

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class ConsumerOrderNacos84 {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerOrderNacos84.class,args);
    }
}

配置类

@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced
    public RestTemplate  getRestTemplate()
    {
        return new RestTemplate();
    }

}

业务类

@Slf4j
@RestController
public class CircleBreakerController {

    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;



    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback") //没有配置
    //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    //@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler="blockHandler",exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id, CommonResult.class,id);

        if (id == 4) {
            throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");
        }else if (result.getData() == null) {
            throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    //fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }

    //blockHandler
    public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }

}
3.7.1.3、测试:
1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、
cloudalibaba-consumer-order-84

#############测试一############
2、浏览器访问:http://localhost:84/consumer/fallback/1

结果:
{"code":200,"message":"from mysql,serverPort:  9004","data":{"id":1,"serial":"aaa"}}
{"code":200,"message":"from mysql,serverPort:  9005","data":{"id":1,"serial":"aaa"}}
两个结果来回切换

3、浏览器访问:http://localhost:84/consumer/fallback/4

结果:
Whitelabel Error Page

#############测试二##############
4、consumer-84业务类放开注解@SentinelResource(value = "fallback",fallback = "handlerFallback")//fallback只负责业务异常

5、浏览器访问:http://localhost:84/consumer/fallback/4

结果:
{"code":444,"message":"兜底异常handlerFallback,exception内容  IllegalArgumentException,非法参数异常....","data":{"id":4,"serial":"null"}}

##############测试三############
6、consumer-84业务类放开注解@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规

7、且sentinel控制台新增fallback的降级策略

新增降级:
	资源名:fallback 策略:异常数	异常数:2 时间窗口:2

8、浏览器访问:http://localhost:84/consumer/fallback/2

结果:正常

浏览器访问:http://localhost:84/consumer/fallback/4

结果:Whitelabel Error Page

快速多次访问:http://localhost:84/consumer/fallback/4

结果:{"code":445,"message":"blockHandler-sentinel限流,无此流水: blockException  null","data":{"id":4,"serial":"null"}}

##################测试四############
9、consumer-84业务类放开注解@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class})

10、浏览器访问:http://localhost:84/consumer/fallback/4

结果:Whitelabel Error Page

浏览器访问:http://localhost:84/consumer/fallback/5

结果:{"code":444,"message":"兜底异常handlerFallback,exception内容  NullPointerException,该ID没有对应记录,空指针异常","data":{"id":5,"serial":"null"}}


结论:

@blockHandlerClass 处理类
@blockHandler 处理类下的处理方法
fallback:处理异常,做服务降级的
exceptionToIgnore:忽略异常

3.7.2、Sentinel与OpenFeign

修改module:cloudalibaba-consumer-order-84

POM新增(上面创建的时候就已增加过了)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

yml新增:

#对Feign的支持
feign:
  sentinel:
    enabled: true

新增feign对应的接口:paymentService

@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService {

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);

}

新增feign接口的对应的服务降级类:PaymentFallbackService

@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
    }
}

新增controller:OrderController

@Slf4j
@RestController
public class OrderController {

    // OpenFeign
    @Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/feign/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSQL(id);
    }


}

主启动类新增注解:

@EnableFeignClients

测试:

1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、
cloudalibaba-consumer-order-84

2、浏览器访问:http://localhost:84/consumer/feign/paymentSQL/5

结果:
{"code":200,"message":"from mysql,serverPort:  9005","data":null}


4、此时关闭cloudalibaba-provider-payment-9004、9005两个微服务,重新访问

结果:
{"code":44444,"message":"服务降级返回,---PaymentFallbackService","data":{"id":5,"serial":"errorSerial"}}

3.8、Sentinel规则持久化

blic CommonResult paymentSQL(@PathVariable(“id”) Long id);

}


新增feign接口的对应的服务降级类:PaymentFallbackService 

```java
@Component
public class PaymentFallbackService implements PaymentService
{
    @Override
    public CommonResult<Payment> paymentSQL(Long id)
    {
        return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
    }
}

新增controller:OrderController

@Slf4j
@RestController
public class OrderController {

    // OpenFeign
    @Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/feign/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
        return paymentService.paymentSQL(id);
    }


}

主启动类新增注解:

@EnableFeignClients

测试:

1、启动nacos-server、sentinel-server、cloudalibaba-provider-payment-9004、9005、
cloudalibaba-consumer-order-84

2、浏览器访问:http://localhost:84/consumer/feign/paymentSQL/5

结果:
{"code":200,"message":"from mysql,serverPort:  9005","data":null}


4、此时关闭cloudalibaba-provider-payment-9004、9005两个微服务,重新访问

结果:
{"code":44444,"message":"服务降级返回,---PaymentFallbackService","data":{"id":5,"serial":"errorSerial"}}

3.8、Sentinel规则持久化

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

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

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

相关文章

QT实战-qt各种菜单样式实现

本文主要介绍了qt普通菜单样式、带选中样式、带子菜单样式、超过一屏幕菜单样式、自定义带有滚动条的菜单样式&#xff0c; 先上图如下&#xff1a; 1.普通菜单样式 代码&#xff1a; m_pmenu new QMenu(this);m_pmenu->setObjectName("quoteListMenu"); qss文…

健康养生生活

在快节奏的现代生活中&#xff0c;健康养生愈发成为人们关注的焦点。它不仅是一种生活方式&#xff0c;更是对生命质量的珍视与呵护。 健康养生&#xff0c;饮食为先。合理的膳食结构是维持身体健康的基石。我们应确保每餐营养均衡&#xff0c;增加蔬菜、水果、全谷物以及优质蛋…

2023年华数杯数学建模B题不透明制品最优配色方案设计解题全过程文档及程序

2023年华数杯全国大学生数学建模 B题 不透明制品最优配色方案设计 原题再现&#xff1a; 日常生活中五彩缤纷的不透明有色制品是由着色剂染色而成。因此&#xff0c;不透明制品的配色对其外观美观度和市场竞争力起着重要作用。然而&#xff0c;传统的人工配色存在一定的局限性…

C语言实验 循环结构2

时间:2024.12.3 一、实验 7-1 求符合给定条件的整数集 #include<stdio.h> int main(){int a,b,s,g; scanf("%d",&a);int h=0; for(int i=a;i<=a+3;i++){for(int j=a;j<=a+3;j++){for(int k=a;k<=a+3;k++){if((i!=j)&&(i!=k)&&…

Android10 设备死机的问题分析和解决

最近客户反馈一个问题&#xff0c;设备偶现死机。最后解决&#xff0c;在此记录。 目录 一死机的现象 二死机的类型 三 死机问题分析 1 死机现象的梳理 2 死机日志 1&#xff09;日志分析一 2 日志分析二&#xff08;正确方案&#xff09; 一死机的现象 设备死机&#x…

koa中间件

文章目录 1. koa中间件简介2. 中间件类型1. 应用级中间件2. 路由级中间件3. 错误处理中间件4. 第三方中间件 3.中间件执行流程 1. koa中间件简介 在Koa中&#xff0c;中间件呈现为一个异步函数&#xff0c;该函数支持 async/await 语法&#xff0c;它接收两个参数&#xff1a;…

python学opencv|读取视频(一)灰度视频制作和保存

【1】引言 上一次课学习了用opencv读取图像&#xff0c;掌握了三个函数&#xff1a;cv.imread()、cv.imshow()、cv.imwrite() 相关链接如下&#xff1a; python学opencv|读取图像-CSDN博客 这次课我们继续&#xff0c;来学习用opencv读取视频。 【2】学习资源 首先是官网…

BioDeepAV:一个多模态基准数据集,包含超过1600个深度伪造视频,用于评估深度伪造检测器在面对未知生成器时的性能。

2024-11-29, 由罗马尼亚布加勒斯特大学创建BioDeepAV数据集&#xff0c;它专门设计来评估最先进的深度伪造检测器在面对未见过的深度伪造生成器时的泛化能力&#xff0c;这对于提高检测器的鲁棒性和适应性具有重要意义。 数据集地址&#xff1a;biodeep 一、研究背景&#xff1…

Apache Airflow 快速入门教程

Apache Airflow已经成为Python生态系统中管道编排的事实上的库。与类似的解决方案相反&#xff0c;由于它的简单性和可扩展性&#xff0c;它已经获得了普及。在本文中&#xff0c;我将尝试概述它的主要概念&#xff0c;并让您清楚地了解何时以及如何使用它。 Airflow应用场景 …

【OpenAI库】从0到1深入理解Python调用OpenAI库的完整教程:从入门到实际运用

文章目录 Moss前沿AI一、初识OpenAI API1.1 获取API-Key&#xff08;两种方案&#xff09;1.2 安装OpenAI库 二、Python调用OpenAI API的基础设置2.1 设置API密钥和Base URL2.2 参数详解 三、构建一个简单的聊天应用3.1 创建聊天请求3.2 参数详解3.3 处理响应 四、完整代码示例…

42 基于单片机的智能浇花系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采样DHT11温湿度传感器检测温湿度&#xff0c;通过LCD1602显示 4*4按键矩阵可以设置温度湿度阈值&#xff0c;温度大于阈值则开启水泵&#xff0c;湿度大于阈值则开启风扇…

typecho 添加主题备份及恢复功能

typecho 换主题很简单&#xff0c;但是确有一个比较麻烦的事情&#xff0c;就是主题配置在切换主题的同时也就被删除了。于是&#xff0c;今天我下决心要弄一个备份恢复的功能出来。网上查了很久&#xff0c;都没有找到适合的&#xff08;不过还是有参考价值的&#xff09;。最…

docker部署RustDesk自建服务器

客户端&#xff1a; Releases rustdesk/rustdesk GitHub 服务端&#xff1a; 项目官方地址&#xff1a;GitHub - rustdesk/rustdesk-server: RustDesk Server Program 1、拉取RustDesk库 docker pull rustdesk/rustdesk-server:latest 阿里云库&#xff1a; docker pu…

从零开始了解推荐系统(算法构建、召回、粗排、精排、重排、冷启动、衡量标准)

算法构建 推荐算法流程 实际上是一种信息处理逻辑&#xff0c;当获取了用户与内容的信息之后&#xff0c;按照一定的逻辑处理信息后&#xff0c;产生推荐结果。热度排行榜就是最简单的一种推荐方法&#xff0c;依赖的逻辑是当一个内容被大多数用户喜欢&#xff0c;那么大概率…

【第 1 章 初识 C 语言】1.8 使用 C 语言的 7 个步骤

目录 1.8 使用 C 语言的 7 个步骤 1.8.1 第 1 步&#xff1a;定义程序的目标 1.8.2 第 2 步&#xff1a;设计程序 1.8.3 第 3 步&#xff1a;编写代码 1.8.4 第 4 步&#xff1a;编译 1.8.5 第 5 步&#xff1a;运行程序 1.8.6 第 6 步&#xff1a;测试和调试程序 1.8.…

基于Matlab卡尔曼滤波的GPS/INS集成导航系统研究与实现

随着智能交通和无人驾驶技术的迅猛发展&#xff0c;精确可靠的导航系统已成为提升车辆定位精度与安全性的重要技术。全球定位系统&#xff08;GPS&#xff09;和惯性导航系统&#xff08;INS&#xff09;在导航应用中各具优势&#xff1a;GPS提供全球定位信息&#xff0c;而INS…

C++知识整理day3类与对象(下)——赋值运算符重载、取地址重载、列表初始化、友元、匿名对象、static

文章目录 1.赋值运算符重载1.1 运算符重载1.2 赋值运算符重载 2.取地址重载2.1 const成员函数2.2 取地址运算符重载 3.类与对象的补充3.1 再探构造函数---初始化列表3.2 类型转换3.3 static成员3.4 友元3.5 内部类3.6 匿名对象3.7 对象拷贝时的编译器优化 1.赋值运算符重载 赋…

深入解析级联操作与SQL完整性约束异常的解决方法

目录 前言1. 外键约束与级联操作概述1.1 什么是外键约束1.2 级联操作的实际应用场景 2. 错误分析&#xff1a;SQLIntegrityConstraintViolationException2.1 错误场景描述2.2 触发错误的根本原因 3. 解决方法及优化建议3.1 数据库级别的解决方案3.2 应用层的解决方案 4. 友好提…

dns实验3:主从同步-完全区域传输

服务器192.168.234.111&#xff08;主服务器&#xff09;&#xff0c;打开配置文件&#xff1a; 打开配置文件&#xff1a; 关闭防火墙&#xff0c;改宽松模式&#xff1a; 重启服务&#xff1a; 服务器192.168.234.112&#xff08;从服务器&#xff09;&#xff0c;打开配置文…

LeetCode刷题 -- 分治快排

目录 颜色分类题目解析算法原理代码 排序数组题目解析算法原理代码 数组中第K个最大元素题目解析算法原理代码 LCR 159. 库存管理 III题目解析算法原理代码 颜色分类 题目链接 题目解析 数组分为三块 算法原理 1.如果nums[i] 0&#xff0c;left, i下标对应元素交换&#xff0c…