SpringCloud Alibaba实战和源码(2)Sentinel

Sentinel介绍

分布式系统的流量防卫兵:随着微服的普及,服务调用的稳定性变得越来越重要。
sentinel以“流量”为切入点,在流量控制、断路、负载保护等多个领域开展工作,保障服务可靠性。
特点:
丰富的应用场景:sentinel承接了阿里10年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可应用等。
完备的实时监控:sentinel同时提供实时的监控功能。可以在控制台中看到接入应用的单台机器秒级数据,甚至500台以下规模的集群的汇总运行情况。
广泛的开源生态:sentinel提供开箱即用的与其他开源框架/库的整合模块,例如与springcloud、apache dubbo 、grpc 、quarkus的整合。只需要引入相对应的依赖并进行简单的配置即可快速地接入sentinel。同时sentinel提供 Java/Go/C++ 等多语言的原生实现。
完善的spi扩展机制:sentinel提供简单易用、完善的SPI扩展接口。可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

官网文档:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

Sentinel优势

在这里插入图片描述
如果一个模块出现不可用导致服务雪崩

服务雪崩
多个微服务之间调用的时候,假设A调用B和C,B和C又调用了其他的微服务,这就是所谓的扇出。如果扇出的某个链路上某个微服务调用的响应时间过程或者不可用,微服务A的调用就占用越来越多的系统资源,从而引起系统崩溃,这就是服务雪崩。这就是服务高可用遭到了破坏

对于高流量的应用来说,单一的后端依赖可能会导致服务器上的所有资源都在几秒钟内饱和。同时还有可能造成这些应用程序导致服务之间的延迟增加,备份列队,线程和其他的系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系失败,不能取消整个应用程序或系统,所以通常发生了一个模块的某个实例失败后,这时候这个模块依然还会接受流量,然后这个有问题的模块还调用其他的模块,这样就会发生级联故障,或者叫做雪崩

要解决这种问题的出现我们就需要用到服务降级,而Sentinel就可以保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,提高分布式系统的弹性。

Sentinel的熔断降级通过断路器实现:

​ 断路器:它本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似于熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法出的异常,这样就保证了服务调用方的不会被长时间、不必要的占用,从而避免了故障在分布式系统中蔓延(类似于病毒传染),从而避免了故障在系统中蔓延,乃至崩溃。

好处体现:

​ 对比与其他的产品而言,比如说Hystrix,他不需要我们自己手动搭建监控平台,而且它有一套类似于Nacos的Web界面,可以让我们进行更加细粒度的配置流控、速率、服务熔断、服务降级等

​ 目前主流编程都是 约定>配置>代码,虽然我们的配置都可以写在代码中,但是我们还是要大面积的学习配置和注解的方式,尽量少些代码,这也是Sentinel的理念和初衷。
在这里插入图片描述
在这里插入图片描述
Sentinel下载和安装
下载地址:https://github.com/alibaba/Sentinel/releases
在这里插入图片描述
官方提供的手册:https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_spring_cloud_alibaba_sentinel

Sentinel 分为两个部分

  • 核心库(Java客户端)不依赖任何框架/库,只需要Java运行时环境,同时对Dubbo/SpringCloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 SpringBoot开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。

启动指令

java -Dserver.port=8858 -Dsentinel.dashboard.auth.username=sentinel  -Dsentinel.dashboard.auth.password=123456  -jar   jar包位置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Sentinel初始化监控

搭建Sentinel项目

  1. Sentinel的官方文档网址:https://sentinelguard.io/zh-cn/docs/quick-start.html
  2. 创建项目
  3. 导入依赖:
<!-- Nacos客户端依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- sentinel依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  1. 配置yaml文件
server:
  port: 8401
spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可
        dashboard: localhost:8858 # 指定控制台服务的地址
management:
  endpoints:
    web:
      exposure:
        include: '*'

流控规则

基本介绍
在这里插入图片描述
名词解释
资源名:唯一名称,默认请求路径

针对来源: sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)

阙值类型/单机阙值:

  • QPS(每秒钟的请求数量):当调用该API的QPS达到阙值的时候,进行限流
  • 线程数:当调用该API的线程数量达到阙值的时候,进行限流

是否集群:当前不需要集群

流控模式

  • 直接:API达到限流条件时,直接限流
  • 关联:当关联的资源达到阙值时,就限制自己
  • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阙值,就进行限流)(API级别的针对来源)

流控效果:

  • 快速失败:直接失败,抛异常
  • warm up:根据codeFactor(冷加载因子,默认3)的值,从阙值/codeFactor,经过预热时长才到达设置的QPS阙值
  • 排队等待:匀速排队,让请求以匀速的速度通过,阙值类型必须设置为QPS,否则无效

QPS直接失败案例
QPS模式
在这里插入图片描述
线程数直接失败
在这里插入图片描述
QPS和线程数区别
QPS为每秒请求个数,并发线程数为每次请求个数
在这里插入图片描述

流控规则-关联

官方解释:当关联的资源达到阙值是,就限流自己
通俗解释来说,比如那我们的程序,现在有testA接口和testB接口,当A关联的资源B达到阈值后,就限流自己,也就是B到达阈值,限流A本身。就好像我家孩子在外面打架,我来处理一样。换到程序里面来说比如一个电商系统中,支付系统达到阈值,就限流下订单系统。

在这里插入图片描述
在这里插入图片描述

流控规则-链路

链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流,它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
比如在一个微服务中,两个接口都调用了同一个Service中的方法,并且该方法用SentinelResource(用于定义资源)注解标注了,然后对该注解标注的资源(方法)进行配置,则可以选择链路模式。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Sentinel流控效果-预热

使用场景:一般秒杀系统中会有这样的流控设置,为了防止秒杀瞬间造成系统崩溃。

概念:Warm Up方式,即预热/冷启动方式。该方式主要用于系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况。

​预热公式:阈值/coldFactor(默认值为3),经过预热时间后才会达到阈值。
在这里插入图片描述
在这里插入图片描述
使用场景:一般秒杀系统中会有这样的流控设置,为了防止秒杀瞬间造成系统崩溃。

Sentinel流控效果-排队等待

排队等待(匀速器):匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

概念:匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

这种方式主要用于处理间隔性突发的流量,例如消息队列(削峰填谷)。想象一下,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求(削峰填谷)

在这里插入图片描述
匀速器
以固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过事件间隔不小于预设值,则让当前请求通过。(请求时间间隔大于预设值直接通过)。否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的timeout时间,则该气球会等待知道预设时间到来通过(排队等待处理);若预期的通过时间超出最大排队时长,则直接拒绝这个请求
在这里插入图片描述
sentinel匀速排队等待策略是漏桶算法结合虚拟队列等待机制实现的。
匀速排队模式暂时不支持QPS>1000的场景。

在这里插入图片描述

熔断降级

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保证高可用的重要措施之一。一个服务常常会掉别的模块,可能是另外一个远程服务、数据库,或者第三方API等。例如,支付的时候,可能需要远程调用银联的API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用
在这里插入图片描述
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

熔断策略
Sentinel 提供了一下几种熔断策略:

  • 满调用比例(SLOW——REQUEST——RATIO):选择以满调用比例作为阙值,需要设置允许的慢调用RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阙值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求响应时间小于设置的慢调用RT则结束熔断,若大于设置的慢掉RT则会再次被熔断。
  • 异常比例(ERROR——RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求书目,并且异常的比例大于阙值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的个请求成功完成(没错误)则结束熔断,否则会再次被熔断。异常比率的阙值范围是【0.0,1.0】,代表0%-100%。
  • 异常数(ERROR——COUNT):当单位统计时长内的异常数目超过阙值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN状态),若接下来的一个请求完成(没有错误)则结束熔断,否则会再次被熔断。
    在这里插入图片描述
    Sentinel在1.8.0版本对熔断降级做了大的调整,可以定义任意时长的熔断时间,引入了半开启恢复支持。下面梳理下相关特性。

熔断状态有三种状态,非别为OPEN、HALF_OPEN、CLOSED
在这里插入图片描述
熔断规则
熔断降级规则包含下面几个重要的属性:
在这里插入图片描述
官方文档网址:https://sentinelguard.io/zh-cn/docs/circuit-breaking.html

Sentinel熔断策略-慢调用比例

在这里插入图片描述
简单理解:
慢调用比例大于阙值且1s内的qps大于最小请求数则直接熔断,熔断时长结束后的第一个请求时长大于RT则继续熔断,反之恢复正常
在这里插入图片描述
举例:
在这里插入图片描述

Sentinel熔断策略-异常比例

异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。
在这里插入图片描述
简单理解:
异常比例大于阙值且1s内的qps大于最小请求数则直接熔断,熔断时长结束后的第一个请求时长大于RT则继续熔断,反之恢复正常
在这里插入图片描述

Sentinel熔断策略-异常数

在这里插入图片描述
简单理解:
异常数大于阙值且1秒内的qps大于最小请求数,则直接熔断
在这里插入图片描述

热点规则sentinel

热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
    热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效

官网:https://sentinelguard.io/zh-cn/docs/parameter-flow-control.html
在这里插入图片描述
在这里插入图片描述
使用@SentinelResource注解
其实这个热点限流其实就是更加细粒度的流控规则,那么如果想使用它就必须要配合对应SentinelResource注解。

Sentinel 提供了 @SentinelResource 注解用于定义资源,它有很多的参数,我们这里主要关注两个参数:

  1. value:代表资源名称,必需项,因为需要通过resource name找到对应的规则,这个是必须配置的
  2. blockHandler:blockHandler 对应处理 BlockException 的方法名称,可选项,访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException

实际案例
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参数索引0实际上代表的就是我们设置的hot1参数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
参数例外项
参数例外项就是可以达到更加细粒度的控制
在这里插入图片描述
演示
在这里插入图片描述
此时的规则为:如果当前hot1值为除5以外的其他值,都会走普通的阈值规则,但是如果一旦hot1的值为5的时候,将会走参数例外项,此时的阈值为200,我们通过浏览器测试,当hot1的值等于5是只要阈值不超过200就不会出现限流。

注意:题我们到现在代码中使用了@SentinelResource注解,此注解处理的是Sentinel控制台配置的异常,通过blockHandler属性设置对应方法来处理和程序本身异常无关。
在这里插入图片描述
系统规则
​ 系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。(整体应用,粒度更粗)

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

系统规则支持一下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1(1分钟平均负载) 作为启发指标,进行自适应系统保护。当系统 load1(1分钟平均负载) 超过设定的启发值(阈值),且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps(秒级统计的最大QPS) * minRt(秒级统计的最小响应时间) 估算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
    在这里插入图片描述

标题自定义限流处理逻辑

  1. @SentinelResource 既可以配置资源名称也可以配置URL
  2. 如果配置了@SentinelResource的blockHandler属性对应方法,出现限流会调用对应方法
  3. 如果没有配置@SentinelResource的blockHandler属性,系统会走默认的限流处理。

问题

  1. 没有体现我们自己的业务要求。
  2. 自定义处理方法和业务代码耦合在一起。
  3. 每个业务方法都添加一个限流处理方法,代码将会加剧膨胀。
  4. 无法实现统一全局处理。

解决:@SentinelResource除了blockHandler可以设置自定义限流处理逻辑方法以外,还提供另外一个属性来设置限流处理逻辑类型blockHandlerClass属性,此属性中设置的方法必需为 static 函数,否则无法解析。

具体逻辑
第一步
创建CustomerBlockHandler类型用于处理自定义限流处理逻辑,首先创建myhandler.CustomerBlockHandler

/**
 * 此类型用来处理限流自定义逻辑
 */
public class CustomerBlockHandler {
    public static String handlerException1(BlockException exception){
        return "handlerException1:系统异常,请稍后重试!";
    }
    public static String handlerException2(BlockException exception){
        return "handlerException2:网络崩溃了,请稍后重试!";
    }
}

第二步
我们在SentinelResourceTestController类型中添加一个接口方法,同时设置@SentinelResource注解和blockHandlerClass属性对应的类型和这个类型中对应的处理方法

/**
* 此方法用到了自定义限流处理类型CustomerBlockHandler
* 中的handlerException1方法来处理限流逻辑。
*/
@GetMapping("/bycustomer")
@SentinelResource(value = "bycustomer",
                  blockHandlerClass = CustomerBlockHandler.class,
                  blockHandler = "handlerException1")
public String bycustomer(){
    return "-----bycustomer";
}

第三步

测试:给bycustomer资源添加限流规则,然后来测试在超过限流阈值时处理方法是否为CustomerBlockHandler中handlerException1来进行处理。
在这里插入图片描述
在这里插入图片描述
对应关系图
在这里插入图片描述

SentinelResource的fallback属性

fallaback函数名称(sentinel熔错机制),可选项,用于在抛出异常的时候提供fallback处理逻辑。fallback函数对所以类型的异常(除了exceptionsToIgnore里面排除掉的异常类型)进行处理。fallback函数签名位置要求

  • 返回值类型必须与原函数返回值类型一致;
  • 方法参数列表需要和原函数一致,或者可以额外多一个Throwable类型的参数用于接受对应的异常
  • fallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

:fallback属性和blockHandler属性的本质不同在于他们作用的异常不同:
blockHandler: 针对违反Sentinel控制台配置的规则时触发BlockException异常时对应处理的属性
fallback: 针对java本身出现的异常进行处理的对应属性。
(fallback用于程序的异常,blockhandler用于流量控制)

案例

@RestController
@Slf4j
public class DemoController {
    //服务提供者URL
    @Value("${service-url.nacos-user-service}")
    private String SERVICE_URL;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/consumer/fallback/{id}")
    public JsonResult<String> fallback(@PathVariable Long id){
        if(id<=3){
            //通过Ribbon发起远程访问,访问9003/9004
            JsonResult<String> result = restTemplate.getForObject(SERVICE_URL+"/info/"+id,JsonResult.class);
            System.err.println(result.getData());
            return result;
        }else{
            throw new NullPointerException("没有对应的数据记录");
        }
    }
    
    //保证方法签名基本保持一致,但是要添加异常类型参数
    public JsonResult<String> fallbackHandler(Long id,Throwable e){
        JsonResult<String> result = new JsonResult<>(444,"出现未知商品id");
        return result;
    }
}

同时配置blockHandler和fallback属性
@SentinelResource属性的时候,同时设置blockHandler属性和fallback属性时,并且同时出现了Sentinel异常和Java异常,这个时候会执行哪个方法?
blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称,可选项。blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

@RestController
@Slf4j
public class DemoController {
    //服务提供者URL
    @Value("${service-url.nacos-user-service}")
    private String SERVICE_URL;

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/consumer/fallback/{id}")
    //同时添加SentinelResource注解的fallback和blockHandler属性
    @SentinelResource(value = "falllback",fallback = "fallbackHandler",blockHandler = "blockHandler")
    public JsonResult<String> fallback(@PathVariable Long id){
        if(id<=3){
            //通过Ribbon发起远程访问,访问9003/9004
            JsonResult<String> result = restTemplate.getForObject(SERVICE_URL+"/info/"+id,JsonResult.class);
            System.err.println(result.getData());
            return result;
        }else{
            throw new NullPointerException("没有对应的数据记录");
        }
    }
    //处理Java异常
    public JsonResult<String> fallbackHandler(Long id,Throwable e){
        JsonResult<String> result = new JsonResult<>(444,"NullPointerException异常");
        return result;
    }

    //处理Sentinel限流
    public JsonResult<String> blockHandler(Long id, BlockException e){
        JsonResult<String> result = new JsonResult<>(445,"BlockException限流");
        return result;
    }
}

在这里插入图片描述

  • 未出发熔断之前的异常交给fallback处理
    在这里插入图片描述
  • 一旦触发熔断规则就变成blockHandler来处理
    在这里插入图片描述
    exceptionsToIgnore属性
    用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入fallback逻辑中,而是会原样抛出。
    @SentinelResource(value = "falllback",fallback = "fallbackHandler",
            exceptionsToIgnore = {NullPointerException.class})//被标注的异常将会被 原样抛出

OpenFeign

OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求,用法其实就是编写一个接口,在接口上添加注解即可。

可以简单理解它是借鉴Ribbon的基础之上,封装的一套服务接口+注解的方式的远程调用器。

OpenFeign能干什么
它的宗旨是在编写Java Http客户端接口的时候变得更加容易,其底层整合了Ribbon,所以也支持负载均衡。

之前我们使用Ribbon的时候,利用RestTemplate对Http请求进行封装处理,但是在实际开发中,由于对服务依赖的调用不可能就一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以OpenFeign在此基础之上做了进一步的封装,由它来帮助我们定义和实现依赖服务接口的定义,我们只需创建一个接口并使用注解的方式来配置它,即可完成对微服务提供方的接口绑定,简化Ribbon的操作。

具体使用

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>${openfeign-version}</version>
</dependency>

YML配置

server:
  port: 8888
spring:
  application:
    name: nacos-consumer-openFeign
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

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

主启动中添加注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//添加此注解
public class CloudalibabaOpenFeignConsumer8888Application {
    public static void main(String[] args) {
        SpringApplication.run(CloudalibabaOpenFeignConsumer8888Application.class, args);
    }
}

调用服务提供者对外提供接口
在这里插入图片描述
service层

/**
 * 此接口就是配合使用OpenFeign的接口,
 * 在此接口中添加@FeignClient接口同时标注
 * 要调用的服务端名称,同时使用与服务提供者
 * 方法签名一致的抽象方法来表示远程调用的
 * 具体内容
 */
@Service
//表示远程调用服务名称
@FeignClient("nacos-provider")
public interface openFeignService {
    /**
     * 此方法表示远程调用info/{id}接口
     */
    @GetMapping("info/{id}")
    public JsonResult<String> msbSql(@PathVariable("id") Long id);
}

控制器

@RestController
public class OpenFeignController {

    @Autowired
    private OpenFeignService openFeignService;

    @GetMapping("getInfo/{id}")
    public JsonResult<String> getInfo(@PathVariable("id") Long id){
        return openFeignService.msbSql(id);
    }

}

测试结果
在这里插入图片描述
OpenFeign超时时间控制
OpenFeign 客户端默认等待1秒钟,但是如果服务端业务超过1秒,则会报错。为了避免这样的情况,我们需要设置feign客户端的超时控制。

解决办法:由于OpenFeign 底层是ribbon 。所以超时控制由ribbon来控制。在yml文件中配置

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ReadTimeout: 5000
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ConnectTimeout: 5000

OpenFeign日志打印
Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign 中 Http 请求的细节。
简单理解,就是对Feign接口的调用情况进行监控和输出

日志级别

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
  • FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

具体使用

@SpringBootApplication
@EnableFeignClients
public class Application {
    ......省略其他代码
	@Bean
    Logger.Level feignLoggerLevel(){
        //开启详细日志
        return Logger.Level.FULL;
    }
}

yaml中的配置

logging:
  level:
    # openfeign日志以什么级别监控哪个接口
    com.mashibing.cloudalibabaopenfeginconsumer8888.service.OpenFeginService: debug

测试效果,发起一次调用以后的日志内容:
在这里插入图片描述

Sentinel整合OpenFegin

引入OpenFegin

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

激活Sentinel对OpenFeign的支持,配置yaml

# 激活SentinelOpenFeign的支持
feign:
  sentinel:
    enabled: true

主启动类要添加@EnableFeignClients注解

@EnableFeignClients//注入Feign

OpenFegin接口编写

//当没有成功调用/info/{id}接口时会走fallback属性标注的类型的处理方法
@Service
@FeignClient(value = "nacos-provider",fallback = FeignServiceImpl.class)
public interface FeignService {
    /**
     * 远程调用对应方法
     */
    @GetMapping("info/{id}")
    public JsonResult<String> msbSql(@PathVariable("id") Long id);
}

fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口

实现类必须添加@Component注解,否则无法注入到容器中

@Component
public class FeignServiceImpl implements FeignService{
    @Override
    public JsonResult<String> msbSql(Long id) {
        return new JsonResult<>(444,"服务降级返回!");
    }
}

控制器

@Autowired
private FeignService feignService;

@GetMapping("getInfo/{id}")
public JsonResult<String> getInfo(@PathVariable("id") Long id){
    if(id > 3){
        throw new RuntimeException("没有该id");
    }
    return feignService.msbSql(id);
}

测试
在这里插入图片描述
在这里插入图片描述

Sentinel持久化配置

在Sentinel Dashboard中配置规则之后重启应用就会丢失,所以实际生产环境中需要配置规则的持久化实现,Sentinel提供多种不同的数据源来持久化规则配置,包括file,redis、nacos、zk。

Sentinel规则持久化到Nacos
将限流规则持久化进Nacos保存,只要刷新8401某个接口地址,Sentinel控制台的流控规则就能感应到,同时只要Nacos里面的配置不删除,针对8401上Sentinel的流控规则就持续有效。
在这里插入图片描述
其实就是实现Sentinel Dashboard与Nacos之间的相互通信

通过Nacos配置文件修改流控规则—拉取—>Sentinel Dashboard界面显示最新的流控规则
**注意:**在Nacos控制台上修改流控制,虽然可以同步到Sentinel Dashboard,但是Nacos此时应该作为一个流控规则的持久化平台,所以正常操作过程应该是开发者在Sentinel Dashboard上修改流控规则后同步到Nacos,遗憾的是目前Sentinel Dashboard不支持该功能。

具体操作
引入依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <!--<version>1.8.1</version>-->
</dependency>

配置YML

# 服务名
spring:
  application:
    name: order
  cloud:
    nacos:
      discovery:
        # nacos注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
      #配置Sentinel的持久化
      datasource: # 配置Sentinel的持久化
        nacos:
          nacos:
            serverAddr: localhost:8848
            groupId: DEFAULT_GROUP
            dataId: order-sentinel.json
            ruleType: flow

进入到Nacos控制台,添加配置
在这里插入图片描述
具体配置内容:

[   
    {
        "resource": "test1",
        "limitApp": "default",
        "grade": 1,
        "count": 2,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
---------------具体内容含义-----------------
resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up2表示排队等待;
clusterMode:是否集群。

控制器

@RestController
public class OrderController {
    @GetMapping("/order/test1")
    @SentinelResource(value = "test1")
    public String test1() throws InterruptedException {
        return "test1 ";
    }
}

测试
重启项目以后,就会在Sentinel界面上看到对应的限流规则
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值