SpringCloudAlibaba Sentinel概念及简单应用

文章目录

    • 1.为什么要有Sentinel?
    • 2.Sentinel下载安装运行
    • 3.Sentinel监控
      • 3.1初始化
      • 3.2 Sentinel流控规则
        • 3.2.1 QPS直接限流
        • 3.2.2线程数直接限流
        • 3.2.3流控模式之关联
        • 3.2.4流控效果之预热
        • 3.2.5流控效果之排队
    • 4. Sentinel降级规则
      • 4.1 Sentinel降级-RT(平均响应时间)
      • 4.2 Sentinel降级-异常比例。
      • 4.3 Sentinel降级-异常数
    • 5.热点Key限流
    • 6. Sentinel系统规则
    • 7.SentinelResource配置
      • 7.1可用于配置限流之后的兜底方法
      • 7.2存在的问题
      • 7.3客户自定义处理逻辑
    • 8. Sentinel服务熔断降级整合ribbon+openFeign+fallback
      • 8.1环境搭建
      • 8.2只配置fallback
      • 8.3只配置blockHandler
      • 8.4 既配置handler也配置blockHandler
      • 8.5服务熔断exceptions ToIgnore
      • 8.6 Sentinel服务熔断+openFeign
    • 9.Sentinel持久化规则

参考尚硅谷

1.为什么要有Sentinel?

之前我们对微服务进行监控,速率控制,服务熔断,服务降级等等都是通过Hystrix来进行的,而Hystrix需要我们程序员自己手工搭建监控平台没有一套Web界面来给我们进行更加细粒度化的配置流控速率控制,服务熔断,服务降级。。。。。现在Sentinel的出现解决了这些问题,它提供了直接界面化的细粒度统一配置。

SpringCloudAlibaba Sentinel概念及简单应用_第1张图片

2.Sentinel下载安装运行

到他的官网github上下载,https://github.com/alibaba/Sentinel/releases/tag/1.7.0,找到那个jar包,下载到本地,然后在命令行中输入java -jar sentinel-dashboard-1.7.0.jar,运行

SpringCloudAlibaba Sentinel概念及简单应用_第2张图片

然后再浏览器中输入http://localhost:8080

SpringCloudAlibaba Sentinel概念及简单应用_第3张图片

看到这个说明安装运行成功。输入用户名密码(sentinel,sentinel)即可登录

3.Sentinel监控

3.1初始化

首先我们新建一个Module,新开一个微服务,并且把这个微服务注册到Nacos中,然后用Sentinel监控他。

在pom中必须导入这三个依赖


        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-datasource-nacosartifactId>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
        dependency>

新建yml

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8080 #配置Sentinel dashboard地址
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: ${spring.application.name}
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

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

这个微服务的端口号是8401,然后我要把他注册进Nacos中,所以要配一个nacos,然后将它用Sentinel进行监控,所以要配一个sentinel的配置。最后那段management是暴露监控端点的。

然后新建主启动类

@EnableDiscoveryClient
@SpringBootApplication
public class CloudalibabaSentinelService8401Application {

    public static void main(String[] args) {
        SpringApplication.run(CloudalibabaSentinelService8401Application.class, args);
        System.out.println("启动成功");
    }

}

controller

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

}

然后启动这个微服务,启动之后登录Nacos查看服务管理能看到这个服务已经被注册到Nacos中

SpringCloudAlibaba Sentinel概念及简单应用_第4张图片

然后看看他能不能被Sentinel监控到登录Sentinel

SpringCloudAlibaba Sentinel概念及简单应用_第5张图片

发现空空如也,这是因为Sentinel采用了懒加载,你访问一下接口他就会出来

SpringCloudAlibaba Sentinel概念及简单应用_第6张图片

SpringCloudAlibaba Sentinel概念及简单应用_第7张图片

然后我们就能在Web界面上看到这个接口的监控效果。

3.2 Sentinel流控规则

3.2.1 QPS直接限流

SpringCloudAlibaba Sentinel概念及简单应用_第8张图片

SpringCloudAlibaba Sentinel概念及简单应用_第9张图片

这个流控模式有三种

1.直接:api达到限流条件直接限流

2.关联:当关联的阈值达到阈值时就限流自己

3.链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)。

资源名就是那个接口的地址,QPS是每秒点击的次数,我配的是1说明我每秒钟最多访问1次,超过了这个阈值就会被限流(如下图所示)。

SpringCloudAlibaba Sentinel概念及简单应用_第10张图片

3.2.2线程数直接限流

我们在流控配置界面里选择的阈值类型改成线程数,然后阈值改为1,当调用api的线程数达到阈值的时候,进行限流。为了测试我们可以在那个接口中加一些延迟。

    @GetMapping("/testA")
    public String testA() {
        // 测试阈值类型:线程数
        try {
            TimeUnit.MILLISECONDS.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "------testA";
    }

在这里插入图片描述

我们先点一下这个接口然后他会阻塞,在这个过程中我们另起一个访问该接口这就意味着有两个线程同时访问了这个接口,我们配置的阈值数是1现在有两个线程所以就是有一个能访问一个被限流。

3.2.3流控模式之关联

首先一点何为关联当流控达到阈值的时候就限流自己, 这个就相当于连坐,比如说你和你同桌打架,明明这事儿不赖你,其实是赖他,但是呢老师在认定责任的时候会认定为这是一起互殴的“刑事案件”,你也得跟着挨说,就相当于B惹事A挂了。这个主要应用在这样一种情形,有一个支付接口它挂了,下订单接口跟着一块挂。

然后我们在sentinel的web界面上配置一下关联模式的流控。

SpringCloudAlibaba Sentinel概念及简单应用_第11张图片

这个说明当B资源每秒钟点击数大于1A就会被限流。一会我们密集访问B,最后你会发现A居然挂了。我们用postman来模拟这个过程,

首先新建一个collection输上url,然后配置一下具体几个线程多长时间访问一次。

在这里插入图片描述

SpringCloudAlibaba Sentinel概念及简单应用_第12张图片

这里我们设置成20个线程每隔0.3秒访问一次。然后我们看一下结果

SpringCloudAlibaba Sentinel概念及简单应用_第13张图片

B满了A就挂了。

3.2.4流控效果之预热

Warm up方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能把整个系统压垮。通过冷启动,让通过的流量缓慢增加,在一定时间内增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。来看一个例子

SpringCloudAlibaba Sentinel概念及简单应用_第14张图片

Warm up有一个默认的coldFactor为3,即请求QPS从(threshold/3)开始,这个案例就是阈值为10预热时长设置为5s,系统初始化的阈值就是3,等5s后阈值慢慢恢复为10。也就是说你一开始1s之内你连点3次或3次以上他就限流等5s之后他的阈值恢复为10,1s之内连点3次就没问题了。

3.2.5流控效果之排队

排队即让请求以均匀的速度通过,阈值类型必须设成QPS,否则无效。来看下面的一个例子。

SpringCloudAlibaba Sentinel概念及简单应用_第15张图片

这个的意思就是/testB每秒1次请求,超过的话就必须排队等待,等待的时间为20000毫秒。这个实际意义就是请求太多别让他一次性打过来,匀速来隔一段时间来一个避免太忙或者太闲。我们继续用之前的postman做多线程测试,10个线程每个1s请求一次。

    @GetMapping("/testB")
    public String testB() {
        log.info(Thread.currentThread().getName() + "\t" + "...testB");
        return "------testB";
    }

我们把线程访问的日志打出来。

SpringCloudAlibaba Sentinel概念及简单应用_第16张图片

能看到他是1s一个。

4. Sentinel降级规则

Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)Sentinel熔断器没有半开状态。(系统自动去检测是否有请求异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用)。

4.1 Sentinel降级-RT(平均响应时间)

平均响应时间(RT)当1s内持续进入5个请求,对应的时刻的平均响应时间均超过阈值,那么在接下来得时间窗口之内对这个方法的调用都会自动地熔断。为了测试这个降级规则我们要在controller里面加上一个testD。

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

首先我们在这个接口上配上降级规则

SpringCloudAlibaba Sentinel概念及简单应用_第17张图片

这个的意思是每个请求给你200毫秒的时间处理,如果这个时间段内处理不完在1s之内会跳闸断电保护我这个系统。

然后我们用JMeter(之前写过略过)测一下我们1s内发送10个请求大于他要求的5了,然后我们要求的时间是200毫秒内处理完,可是我们的接口D中阻塞时间是1s一定处理不完所以在1s内我要让微服务不可用也就是跳闸断电。

SpringCloudAlibaba Sentinel概念及简单应用_第18张图片

停掉JMeter之后一段时间之后再访问就会恢复正常。

SpringCloudAlibaba Sentinel概念及简单应用_第19张图片

4.2 Sentinel降级-异常比例。

异常比例:当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的时间窗口之内对这个方法的调用都会自动的返回,异常比率的阈值范围是[0.0,1.0],代表0%~100%。

将之前的testD接口方法的阻塞1s改成异常。

    @GetMapping("/testD")
    public String testD() {
        log.info("testD 异常比例");
        int age = 10/0;
        return "------testD";
    }

SpringCloudAlibaba Sentinel概念及简单应用_第20张图片

这个的意思就是正确的比例必须在0.8以上不然的话会熔断。然后我们还是通过JMeter访问testD接口进行测试testD接口一定会抛异常,那这样的话异常率就是%100所以这个testD会被降级。

SpringCloudAlibaba Sentinel概念及简单应用_第21张图片

当我停掉JMeter时我再次访问这次我只发一个请求小于所要求的5个请求所以不会走熔断,会直接报异常。

SpringCloudAlibaba Sentinel概念及简单应用_第22张图片

4.3 Sentinel降级-异常数

当资源近1分钟的异常数目超过阈值之后进行熔断,(这次的统计窗口一定是分钟级别的因为如果小于60s,结束熔断后会再次熔断)。

SpringCloudAlibaba Sentinel概念及简单应用_第23张图片

我们配置这个降级规则就是当异常数超过5他才会降级,如果小于5会直接抛异常,降级之后的70s后再次访问会重新报错。为了演示这个现象我们新增一个接口testE这个会抛出异常。

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

我们连点5次。。。服务降级。

SpringCloudAlibaba Sentinel概念及简单应用_第24张图片

等一会(过了时间窗口)再次访问。

SpringCloudAlibaba Sentinel概念及简单应用_第25张图片

5.热点Key限流

这个就是对于经常访问的数据为了不让他崩,很多时候我们希望统计某个热点数据中访问频次最高的TopK数据,并对其访问进行限制,比如说某一个商品ID经常被访问到你就要对这个进行限流。热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源进行限流。 限流之后的降级需要一个兜底方法,这个兜底方法Sentinel默认的都是返回一个字符串Blocked by Sentinel (flow limiting)其实这个兜底方法也可以我们自定义类似于hystrix,某个方法出问题了就找对应的兜底方法,hystrix有@HystrixCommand,Sentinel有@SentinelResource通过这个注解我们可以指定方法让他发生降级的时候用指定的方法处理。

@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) {
    return "------testHotKey";
}

public String deal_testHotKey(String p1, String p2, BlockException exception) {
    //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    return "------deal_testHotKey,o(╥﹏╥)o";
}

@SentinelResoure这个注解value你写啥都行只要他唯一就行,blockHandler里面写上兜底方法的方法名,然后当发生降级的时候就会调用这个兜底方法。

SpringCloudAlibaba Sentinel概念及简单应用_第26张图片

这个是配置规则资源名的意思就是@SentinelResource这个注解的value值,然后限流模式它只支持QPS,参数索引你一会访问的时候你可以选择两个参数(根据之前的testHotKey方法),按顺序下标即索引,这里配置成0说明,0这个是热点key不是别的,只有0号参数可能被限流,单机阈值就是当1s超过访问1次就限流。超过统计窗口时长后恢复正常。

SpringCloudAlibaba Sentinel概念及简单应用_第27张图片

假如说我把访问参数换了换成p2那么他永远不会限流

SpringCloudAlibaba Sentinel概念及简单应用_第28张图片

热点key限流控制的特例,有些时候你既想限流又不想限流 之前演示的p1限流每秒达到访问阈值时就会被限流,但是现在我想让他在p1等于一个特定值得时候他的阈值可以达到很高。我们需要在配置当中添加参数例外项。

SpringCloudAlibaba Sentinel概念及简单应用_第29张图片

我们添加参数例外项标记好类型,然后当这个参数为5时,1s内不超过200次访问就不会降级。

SpringCloudAlibaba Sentinel概念及简单应用_第30张图片

6. Sentinel系统规则

Sentinel还可以做系统级别的规则,就是在各种服务接口的基础上再包上一层,如果达到最外层的阈值那么整个系统(服务)都会被停用。

SpringCloudAlibaba Sentinel概念及简单应用_第31张图片

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。(摘自官网)。

7.SentinelResource配置

7.1可用于配置限流之后的兜底方法

之前已经介绍过关于这个注解的使用,这个注解比较常用的两个参数一个是value就是资源名用于在界面配置,另一个是blockHandler,就是兜底方法,如果你配置了兜底方法他就会使用兜底方法,如果没有配置就会返回系统默认的Blocked By Sentinel(flow limit)。

7.2存在的问题

业务代码与兜底方法都写在一起严重耦合,业务类也会逐渐膨胀。

7.3客户自定义处理逻辑

我们需要让业务代码和兜底方法解耦合防止业务逻辑膨胀,所以我们需要在我们的controller包的同级包创建一个myhandler,写上我们自己的CustomerBlockHandler。同时我们在controller这增加一个测试的方法

public class CustomerBlockHandler {


    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 = "handlerException2")
    public CommonResult customerBlockHandler() {
        return new CommonResult(200, "按客戶自定义", new Payment(2020L, "serial003"));
    }

然后我们给customerBlockHandler配置限流规则,在customerBlockHandler()这个方法中上面配置@SentinelResource这个注解标注资源名value,blockHandlerClass表示异常处理的Handler,blockHandler代表的是降级的兜底方法。当触发降级条件的时候@SentinelResource就会起作用,就会找到blockHandlerClass中配置的类,再找到里面的blockHandler所指向的方法。

SpringCloudAlibaba Sentinel概念及简单应用_第32张图片

新增之后我们访问这个接口,狂点

SpringCloudAlibaba Sentinel概念及简单应用_第33张图片

发现果然是找的blockHandlerClass所对应的类和blockHandler所对应的方法。我们可以通过这种方式实现业务方法与兜底方法的解耦。

8. Sentinel服务熔断降级整合ribbon+openFeign+fallback

8.1环境搭建

我们需要一个消费者84,两个生产者9003,9004,把这三个都注册到Nacos服务中心里,通过消费者以负载均衡的方式轮询访问9003,9004。这个配置跟之前nacos的差不多不细说了,看一下业务代码。

9003,9004

@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, "28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L, new Payment(2L, "bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L, new Payment(3L, "6ua8c1e3bc2742d8848569891xt92183"));
    }

    @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;
    }
}

9003,9004都一个样就是输出的端口号不一样,然后咱就是演示一下就不用数据库了,拿那个static代码块里头的东西当数据库就完了。

然后是消费者84端

controller层

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    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;
    }
}

service层

@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
    @GetMapping(value = "/paymentSQL/{id}")
    CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}

config层

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

然后看看效果能不能实现

在这里插入图片描述

在这里插入图片描述

一次9003一次9004实现了最初的设想。

然后我们再访问接口4和5它会在页面上返回报错信息比如4这个

SpringCloudAlibaba Sentinel概念及简单应用_第34张图片

但是我们并不希望给用户看到这些,所以我们要实现我们自己的服务熔断的规则,自己实现兜底方法。

8.2只配置fallback

fallback管的是java的异常。

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    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);
    }
}

在这里插入图片描述

我们再去访问这个接口你会发现舒服多了。。。。

8.3只配置blockHandler

我们再看一下只配置blockHandler的,这个管的是sentinel异常需要在sentinel里面配置。

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    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;
    }
    //本例是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);
    }
}

SpringCloudAlibaba Sentinel概念及简单应用_第35张图片

我们新增一个降级规则有一个异常就走兜底方法。

在这里插入图片描述

8.4 既配置handler也配置blockHandler

既然handler管的是java异常,blockHandler管的是sentinel配置异常,那么这两个都配置的情况下,到时候该听谁的。

SpringCloudAlibaba Sentinel概念及简单应用_第36张图片

我们在fallback这个资源上配置一个流控规则,如果QPS超过1那就降级。然后我们正常访问5这个接口按理说应该是java业务上的异常果然被fallback捕获到了,然后我们加快速度,让他超过流控的阈值,再看一下。

在这里插入图片描述

在这里插入图片描述

可以看出超过阈值的时候走的是sentinel相关的降级规则blockHandler这个兜底方法。

8.5服务熔断exceptions ToIgnore

我们在@SourceResoure这个注解加上这个配置项里面规定配置的异常,那么这个异常不会走blockHandler的兜底方法。

    @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;
    }

当我规定exceptionsToIgnore为IllegalArgumentException.class时说明IllegalArgumentException异常不会被兜底方法处理,会直接抛出异常给用户。

SpringCloudAlibaba Sentinel概念及简单应用_第37张图片

8.6 Sentinel服务熔断+openFeign

我们在消费端的yml文件中激活Sentinel对openFeign的支持

feign:
  sentinel:
    enabled: true

然后service中加上@FeignClient注解,再加一个处理降级的Service类。

@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
    @GetMapping(value = "/paymentSQL/{id}")
    CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}

controller中的相应的方法

    @Resource
    private PaymentService paymentService;

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

如果没有服务提供者宕机,等一些异常情况他会寻找value服务的方法,如果出现宕机或者其他异常将会走fallback配置的类里面的方法。

比如说我开启消费者84和服务提供者9003然后我访问localhost:84/consumer/paymentSQL/1他就会到nacos-payment-provider服务里找到相应的方法去调用

在这里插入图片描述

当我把9003服务提供者宕机之后再看看结果

SpringCloudAlibaba Sentinel概念及简单应用_第38张图片

他会走fallback的类中的降级方法返回给用户一个友好提示,而不是直接报错。这个跟hystrix差不多,hystrix消费侧导入的是hystrix的相关依赖,sentinel消费侧导入的是sentinel的相关依赖。

9.Sentinel持久化规则

@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 服务不可用");
    }
}

看这段代码然后在Sentinel界面中配置他的限流规则。

SpringCloudAlibaba Sentinel概念及简单应用_第39张图片

1s钟访问阈值超过1就会执行自定义的handleException方法。

SpringCloudAlibaba Sentinel概念及简单应用_第40张图片

但是当我把服务暂停之后再次查看Sentinel web界面。

SpringCloudAlibaba Sentinel概念及简单应用_第41张图片

发现空空如也,说明一旦我们重启应用,sentinel配置的规则将会消失,生产环境需要将配置规则进行持久化。

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

我们需要修改8401的pom文件,添加将sentinel一些配置持久化进nacos的依赖

        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-datasource-nacosartifactId>
        dependency>

然后修改8401的yml文件

SpringCloudAlibaba Sentinel概念及简单应用_第42张图片

添加一下红框的部分

然后我们在nacos配置列表中配置sentinel的流控规则,DataID就是服务名称,然后底下的选择json把这段粘上去

SpringCloudAlibaba Sentinel概念及简单应用_第43张图片

然后发布,然后我们重启一下8401,访问一下对应的资源,快点几次,超过他的阈值触发他的限流

SpringCloudAlibaba Sentinel概念及简单应用_第44张图片

然后我们把8401关了再看看sentinel控制台。

SpringCloudAlibaba Sentinel概念及简单应用_第45张图片

再重启多次访问/rateLimit/byUrl,然后再看看。它神奇的回来了

在这里插入图片描述

同时仍然能对这个资源进行限流,所以我们可以将限流规则写进nacos这样能实现持久化。

你可能感兴趣的:(spring,cloud,微服务,java)