四、SpringCloud-服务容错-4

Sentinel–服务容错

一、⾼并发带来的问题

在微服务架构中,我们将业务拆分成⼀个个的服务,服务与服务之间可以 相互调⽤,但是由于⽹络原因或者⾃身的原因,服务并不能保证服务的100%可 ⽤,如果单个服务出现问题,调⽤这个服务就会出现⽹络延迟,此时若有⼤量的⽹络涌⼊,会形成任务堆积,最终导致服务瘫痪。

二、⾼并发问题案例演示

前期准备

启动nacos服务

image-20230829132024449

⼀.创建⼀个服务提供者项⽬,在controller书写两个⽅法供消费者调⽤,⼀个⽅法被延迟,另⼀个⽅法正常。

搭建项目

image-20230829132438120

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

配置文件

server:
  port: 8091
spring:
  application:
    name: example-sentinel-provider
  cloud:
    nacos:
      discovery:
        namespace: 0e2f3694-d3ef-4a39-8aa6-5622872228ce
        server-addr: 192.168.65.3:8848

controller包

image-20230829133441040

@Slf4j
@RequestMapping("/provider")
@RestController
public class ProviderController {
    @SneakyThrows
    @GetMapping("/a")
    public String a() {
        log.info("This is ProviderController`a method!");
        Thread.sleep(2000);
        return "This is ProviderController`a method!";
    }

    @GetMapping("/b")
    public String b() {
        log.info("This is ProviderController`b method!");
        return "This is ProviderController`b method!";
    }
}

启动类

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudExampleSentinelProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudExampleSentinelProviderApplication.class, args);
    }
}

⼆.创建⼀个服务消费者项⽬,在controller书写两个⽅法调⽤服务提供者的⽅法,⼀个会阻塞,⼀个正常。

搭建项目

image-20230829132631848

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

配置文件

server:
  port: 8091
spring:
  application:
    name: example-sentinel-consumer
  cloud:
    nacos:
      discovery:
        namespace: 0e2f3694-d3ef-4a39-8aa6-5622872228ce
        server-addr: 192.168.65.3:8848

service包

public interface ConsumerService {
    String a();
    String b();
}
@Service
public class ConsumerServiceImpl implements ConsumerService {
    @Resource
    private ProviderFeign providerFeign;

    @Override
    public String a() {
        return providerFeign.a();
    }

    @Override
    public String b() {
        return providerFeign.b();
    }
}

feign包

@FeignClient(value = "example-sentinel-provider")
public interface ProviderFeign {
    @GetMapping("/provider/a")
    String a();

    @GetMapping("/provider/b")
    String b();
}

controller包

image-20230829133501274

@Slf4j
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
    @Resource
    private ConsumerService consumerService;
    @GetMapping("/a")
    public String a(){
        log.info("访问了ConsumerController`a method!");
        return consumerService.a();
    }
    @GetMapping("/b")
    public String b(){
        log.info("访问了ConsumerController`b method!");
        return consumerService.b();
    }
}

启动类

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class SpringCloudExampleSentinelConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudExampleSentinelConsumerApplication.class,args);
    }
}

三.修改消费者的tomcat的最⼤线程数

server:
  port: 8096
  tomcat:
    threads:
      max: 10	#tomcat的最大线程数,模拟高并发

四.安装JMeter软件模拟⾼并发来进⾏压⼒测试

1.在官⽹下载:https://jmeter.apache.org/

2.解压,并修改bin中的⽂件jmeter.properties中的语⾔为zh_CN(39⾏左右)

image-20230829131532535

3.启动jmeter.bat⽂件

image-20230829131106527

4.添加线程组

image-20230829124601078

自动跳出

image-20230829131145373

5.配置线程并发数

image-20230829142655495

image-20230829124623193

6.添加HTTP取样

image-20230829124732334

7.配置取样,并启动测试

image-20230829124647505

image-20230829142903050

image-20230829143009155

image-20230829143043704

8.访问正常的请求url查看效果

image-20230829143645038

9.大量的请求进来

image-20230829143936079

10.请注意,测试完关闭

image-20230829143407042

结论:

此时会发现,由于a⽅法囤积了⼤量请求,导致b⽅法的访问出现了问题, 这就是服务雪崩的雏形。

三、服务雪崩效应

在分布式系统中,由于⽹络原因或⾃身的原因,服务⼀般⽆法保证100%可 ⽤。如果⼀个服务出现了问题,调⽤这个服务就会出现线程阻塞的情况,此时 若有⼤量的请求涌⼊,就会出现多条线程阻塞等待,进⽽导致服务瘫痪。 由于服务于服务之间的依赖性,故障会传播,会对整个微服务系统造成灾 难性的严重后果,这就是服务故障的“雪崩”效应。

image-20230829124837073

雪崩发⽣的原因多种多样,有不合理的容量设计,或者是⾼并发下某⼀个⽅法 响应变慢,亦或是某台机器的资源耗尽。我们⽆法完全杜绝雪崩源头的发⽣, 只有做好⾜够的容错,保证在⼀个服务发⽣问题,不会影响到其他服务的正常 运⾏。也就是“雪落⽽不雪崩”。

常⻅容错⽅案

要防⽌雪崩的扩散,我们就要做好服务的容错,容错说⽩了就是保护⾃⼰ 不被猪队友拖垮的⼀些措施,下⾯介绍常⻅的服务容错思路和组件。 常⻅的容错思路有隔离、超时、限流、熔断、降级这⼏种,下⾯分别介绍⼀下。

  1. 隔离

    它是指将系统按照⼀定的原则划分为若⼲服务模块,各个模块之间相对独 ⽴,⽆强影响。当有故障发⽣时,能将问题和影响隔离在某个模块内部, ⽽不扩散⻛险,不波及其他模块,不影响整体的系统服务。常⻅的隔离⽅ 式有:线程池隔离和信号量隔离。

image-20230829124936623

  1. 超时

    在上游(A服务)服务调⽤下游(B服务)服务的时候,设置⼀个最⼤响应 时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。

image-20230829125008768

  1. 限流

    限流就是限制系统的输⼊和输出流量已达到保护系统的⽬的。为了保证系 统的稳固运⾏,⼀旦达到的需要限制的阈值,就需要限制流量并采取少量 措施以完成限制流量的⽬的。

image-20230829125052206

  1. 熔断

    在互联⽹系统中,当下游(B服务)服务因访问压⼒过⼤⽽响应变慢或失 败,上游(A服务)服务为了保护系统整体的可⽤性,可以暂时切断对下 游服务的调⽤。这种牺牲局部,保全整体的措施就叫做熔断。

服务熔断⼀般有三种状态:

a. 熔断关闭状态(Closed)

B服务没有故障时,熔断器所处的状态,对调⽤⽅(A服务)的调⽤ 不做任何限制。

b. 熔断开启状态(Open)

B服务有故障时,后续对该服务接⼝的调⽤不再经过⽹络(不在对B 服务进⾏访问),直接执⾏本地的fallback的⽅法。

c. 半熔断状态(Half-Open)

尝试恢复服务调⽤,允许有限的流量调⽤该服务,并监控调⽤成功 率。如果成功率达到预期,则说明服务已恢复,进⼊熔断关闭状态; 如果成功率仍旧很低,则重新进⼊熔断开启状态。

  1. 降级

    降级其实就是为服务提供⼀个托底(备选)⽅案,⼀旦服务⽆法正常调 ⽤,就使⽤托底(备选)⽅案。

image-20230829125354514

四、常⽤的容错组件

  1. Hystrix:由NetFlix开源的⼀个延迟和容错库,⽤于隔离访问远程系统、 服务或者第三⽅库,防治级联失败,从⽽提升系统的可⽤性与容错性。
  2. Resilience4J:是⼀款⾮常轻量、简单,并且⽂档⾮常清晰、丰富的熔断 ⼯具,这也是Hystrix官⽅推荐的替代产品。不仅如此,Resilience4J还原 ⽣⽀持SpringBoot1.x/2.x,⽽且监控也⽀持和prometheus等多款主流产品 进⾏整合。
  3. Sentinel:是阿⾥巴巴开源的⼀款断路器实现,本身在阿⾥内部已经被⼤规模采⽤,⾮常稳定。

image-20230829125438367

五、Sentinel⼊⻔

1、什么是Sentinel

Sentinel(分布式系统的流量防卫兵)是阿⾥开源的⼀套⽤于“服务容错”的综合性解决⽅案,它以流量为切⼊点,从流量控制、熔断降级、系统负载保护等 多个维度来保护服务的稳定性。

官⽅⽹站:https://github.com/alibaba/Sentinel/

Sentinel具有以下特征:

  1. 丰富的应⽤场景:Sentinel承接了阿⾥巴巴近10年的双⼗⼀⼤促流量的核 ⼼场景,例如秒杀(突发流量控制在系统容量可以承受的范围)、消息 削峰填⾕、集群流量控制、实时熔断下游不可⽤应⽤等。
  2. 完备的实时监控:Sentinel提供了实时的监控功能。通过控制台可以看到 接⼊应⽤的单台机器秒级数据,甚⾄500台以下规模的集群的汇总运⾏情 况。
  3. ⼴泛的开源⽣态:Sentinel提供开箱即⽤与其他开源框架/库的整合模 块,例如Spring Cloud、Dubbo、gRPC的整合。只需要引⼊相应的依赖并 进⾏简单的配置即可快速地接⼊Sentinel。
  4. 完善的SPI扩展点:Sentinel提供简单易⽤、完善的SPI扩展接⼝,你可以 通过实现扩展接⼝来快速地定制逻辑。例如定制规则管理、适配动态数 据源等。

Sentinel分为两个部分:

  1. 核⼼库(Java客户端)不依赖任何框架/库,能够运⾏于所有Java运⾏环 境,同时对Dubbo/Spring Cloud等框架也有较好的⽀持。
  2. 控制台(Dashboard)基于Spring Boot开发,打包后可以直接运⾏,不需 要额外的Tomcat等应⽤容器。

2、微服务集成Sentinel

为微服务集成Sentinel⾮常简单,只需要加⼊Sentinel的依赖就⾏。本次演示代码 都集中在消费端,sentinel在正常使⽤中可以添加到服务提供者或者服务消费者 的任意模块中。

  1. 在消费者的pom.xml中引⼊相关依赖

image-20230829125756902

  1. 编写⼀个controller测试使⽤

3、安装Sentinel控制台

Sentinel提供⼀个轻量级的控制台,它提供机器发现、单机资源实时监控以 及规则管理等功能。

  1. 下载jar包,存放到任意⽂件夹 https://github.com/alibaba/Sentinel/releases (用迅雷下载)image-20230829134158334
  2. 通过cmd命令启动控制台(指定端口号启动,默认是8080,避免端口冲突)

image-20230829125913564

java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar

image-20230829134946192

image-20230829134920220

3.修改“消费者项⽬”,在⾥边加⼊有关控制台的配置

image-20230829130013793

spring:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8888
  1. 打开浏览器输⼊以下⽹址,默认⽤户名密码都是sentinel

    https://localhost:8080

image-20230829130124616

注意事项:

  1. 需要⾸先启动Nacos服务端后才可使⽤
  2. Sentinel是懒加载模式,消费者启动后不会实时被Sentinel监控,需访问⼀ 次后才可看到。

4、⼊⻔体验----实现⼀个接⼝的限流

  1. 通过控制台为/customer/b请求添加⼀个流控规则

image-20230829144221856

QPS每秒查询率(Query Per Second) 是对⼀个特定的查询服务器在规定时 间内所处理流量多少的衡量标准,在因特⽹上,作为域名系统服务器的 机器的性能经常⽤每秒查询率来衡量,即每秒的响应请求数,也即是最 ⼤吞吐能⼒。

  1. 通过浏览器快速频繁访问,观察效果

image-20230829144348749

六、Sentinel的概念和功能

1、基本概念

  1. 资源:是Sentinel的关键概念。它可以是Java应⽤程序中的任何内容,可以是⼀个服务,也可以是⼀个⽅法,甚⾄可以是⼀段代码。就是Sentinel 需要保护的东⻄。

    ⼊⻔案例中的customer/b⽅法就可以认为是⼀个资源

  2. 规则:作⽤在资源之上,定义以什么样的⽅式保护资源,主要包括流量 控制规则、熔断降级规则以及系统保护规则。规则就是⽤来定义如何进 ⾏保护资源的。

    ⼊⻔案例就是为customer/b资源设置了⼀种流控规则,限制了进⼊ customer/b的流量

2、重要功能

image-20230829144603258

Sentinel的主要功能就是容错,主要体现为下⾯这三个:

  1. 流量控制:在⽹络传输中是⼀个常⽤的概念,它⽤于调整⽹络包的数 据。任意时间到来的请求往往是随机不可控的,⽽系统的处理能⼒是有 限的。我们需要根据系统的处理能⼒对流量进⾏控制。Sentinel可以根据 需要把随机的请求(数)调整成合适的形状(⼀定的请求数)。

    ⽬的 :保证⾃⼰不被上游服务压垮。

image-20230829144659942

  1. 熔断降级:当检测到调⽤链路中某个资源出现不稳定的表现,例如请求 响应时间⻓或异常⽐例升⾼的时候,则对这个资源的调⽤进⾏限制,让 请求快速失败,避免影响到其它的资源⽽导致级联故障。

    ⽬的:保证⾃ ⼰不被下游服务拖垮。

    Sentinel 对这个问题采取了两种⼿段:

    通过并发线程数进⾏限制:

    和资源池隔离的⽅法不同,Sentinel 通过限制 资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没 有线程切换的损耗,也不需要您预先分配线程池的⼤⼩。当某个资源出现 不稳定的情况下,例如响应时间变⻓,对资源的直接影响就是会造成线程 数的逐步堆积。当线程数在特定资源上堆积到⼀定的数量之后,对该资源 的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

    通过响应时间对资源进⾏降级:

    除了对并发线程数进⾏控制以外, Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出 现响应时间过⻓后,所有对该资源的访问都会被直接拒绝,直到过了指定 的时间窗⼝之后才重新恢复。

  2. 系统负载保护:当系统负载较⾼的时候,如果还持续让请求进⼊可能会 导致系统崩溃,⽆法响应。在集群环境下,会把本应这台机器承载的流 量转发到其它的机器上去。如果这个时候其它的机器也处在⼀个边缘状 态的时候,Sentinel 提供了对应的保护机制,让系统的⼊⼝流量和系统的 负载达到⼀个平衡,保证系统在能⼒范围之内处理最多的请求。

    ⽬的:保证外界环境良好(CPU、内存)。

总之⼀句话:我们需要做的事情,就是在Sentinel的资源上配置各种各样的规 则,来实现各种容错的功能

七、Sentinel规则

1、流控规则

流控控制,其原理是监控应⽤流量的QPS(每秒查询率)或并发线程数等指标,当达到指定的阈(yu)值时对流量进⾏控制,以避免被瞬时的流量⾼峰冲垮,从⽽保障应⽤的⾼可⽤性。

image-20230829145737922

  • 资源名:唯⼀名称。默认请求路径
  • 针对来源:Sentinel可以针对调⽤者进⾏限流,填写微服务名,默认 default (不区分来源)
  • 阈值类型/单机阈值
  1. QPS(每秒钟的请求数量):当调⽤该api的QPS达到阈值的时候, 进⾏限流。
  2. 线程数:当调⽤该api的线程数达到阈值的时候,进⾏限流。(可以 使⽤jMeter模拟多线程)
  • 是否集群:不需要集群
  • 流控模式:
  1. 直接(默认):当前请求达到限流条件时,直接限流
  2. 关联:当关联的资源达到阈值时,就限流⾃⼰,⼀般适合做应⽤让步

image-20230829150026253

3.链路:只记录指定链路上的流量(指定资源从⼊⼝资源进来的流量,如果达到阈值,就进⾏限流),可看作api级别的针对来源,链路的粒度更 细,需要如下步骤才能实现

​ 1.创建service下的实现类,写⼊具体⽅法

image-20230829150116490

​ 2.在Sentinel控制台添加链路设置

image-20230829150143879

​ 3.在yml⽂件中设置链路开启(2.1.1版本后才能使⽤)

image-20230829150200574

流控效果:

  1. 快速失败:直接失败,抛异常,不做任何额外的处理,是最简单 的效果。
  2. Warm up(预热):它从开始阈值到最⼤QPS阈值会有⼀个缓冲阶 段,⼀开始的阈值是最⼤QPS阈值的1/3,然后慢慢增⻓,直到最 ⼤阈值,适⽤于将突然增⼤的流量转换为缓步增⻓的场景。
  3. 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数 量,其余的排队等待;它还会让设置⼀个超时时间,当请求超过时间还未处理,则会被丢弃。

2、降级规则

降级规则就是设置当满⾜什么条件的时候,对服务进⾏降级。Sentinel提供了三 个衡量条件:

  • 慢调⽤⽐例:当资源的响应时间超过最⼤RT(以ms为单位,最⼤RT即最 ⼤响应时间)之后,资源进⼊准降级状态。如果接下来1ms内持续进⼊5 个请求(最⼩请求数),他们的RT都持续超过这个阈值,那么在接下的 熔断时⻓(以s为单位)之内,就会对这个⽅法进⾏服务降级。

image-20230829150409191

  • 异常⽐例:当资源的每秒异常总数占通过量的⽐值数超过阈值之后,资 源进⼊降级状态,即在接下来的熔断时⻓之内,对这个⽅法的调⽤都会 ⾃动地返回。异常⽐率的阈值范围是[0.0,1.0]。

image-20230829150438314

image-20230829150451906

  • 异常数:当资源近统计时⻓的异常数⽬超过阈值(异常数)之后会进⾏服务降级。

image-20230829150519562

3、热点规则

热点参数流控规则是⼀种更细粒度的流控规则,它允许将规则具体到参数上。

  • 编写具体代码

image-20230829150601166

  • 配置热点规则

image-20230829150628553

  • 配置⾼级规则

image-20230829150711126

热点规则相⽐较前⼏种,使⽤较少,处理的为形式参数的问题,甚⾄于更 细分到参数值的阈值。

4、授权规则

很多时候,我们需要根据调⽤来源来限制资源是否通过,这时候可以使⽤ Sentinel的⿊⽩名单的功能,⿊⽩名单根据资源的请求来源(origin)限制资源 是否通过。

  • 若配置⽩名单则只有请求来源位于⽩名单内时才可通过。
  • 若配置⿊名单则请求来源位于⿊名单时不通过,其余的请求通过。

实现步骤:

  1. 创建⼀个类,实现接⼝RequestOriginParser,重写⽅法

image-20230829150824945

  1. 在Sentinel控制台中进⾏授权规则设置

image-20230829150848247

授权规则,根据匹配参数⾥⾯的参数的类型是否匹配参数条件来进⾏限制访问。

5、系统规则

系统保护规则是从应⽤级别的⼊⼝流量进⾏控制,从单台机器的总体Load、 RT、⼊⼝QPS、CPU使⽤率和线程数五个维度监控应⽤数据,让系统尽可能跑在 最⼤吞吐量的同时保证系统整体的稳定性。这个规则和前边四个规则最⼤的区 别在于系统规则是从应⽤级别⼊⼿,⽽其他规则是从资源收⼊的。

  • LOAD:只有在 Linux 系统的机器上才会⽣效,可以根据当前操作系统的 负载,来决定是否触发保护(把请求拒绝掉);
  • RT(响应时间):当单台机器上所有⼊⼝流量的平均RT达到阈值即触发 系统保护,单位是毫秒;
  • 线程数:当单台机器上所有的请求消耗的线程数加起来,如果超过某个 值,就停⽌新的请求;
  • ⼊⼝ QPS:当单台机器上所有接⼝的 QPS 加起来,如果超过某个值,就 停⽌新的请求;
  • CPU 使⽤率:当单台机器上所有⼊⼝流量的CPU 的使⽤率,如果超过⼀ 个百分⽐,就停⽌新的请求;

image-20230829151002782

⼀般情况下,系统规则使⽤很少,⼀般是在运维中使⽤⽐较多⼀些。

6、自定义异常返回

通过⾃定义异常返回,可以根据限流类型返回特定内容的⻚⾯。

  1. 创建⼀个类,实现BlockExceptionHandler接⼝

image-20230829151110134

  1. 重写handle⽅法

image-20230829151136710

  1. 再次刷新限流⻚⾯

image-20230829151156382

八、@SentinelResource的使⽤

Sentinel 提供了 @SentinelResource 注解⽤于定义资源,并提供了AspectJ的扩展 ⽤于⾃动定义资源、处理BlockException、其他异常情况等。

  • 定义了资源
  • 定义当资源内部发⽣异常的时候的处理逻辑

常⻅属性

image-20230829151317683

这⾥我们着重讲解当发⽣异常后处理逻辑

  1. 创建⼀个资源定义⽅法

image-20230829151412463

  1. 书写处理blockException的处理逻辑

image-20230829151433605

  1. 书写处理其他异常的处理逻辑(兜底⽅法)

image-20230829151500942

实际开发当中经常出现,服务限流,但是超出规则的默认返回提示,这样不太 符合业务逻辑。可以使⽤blockHandler 来指定⼀个出现异常的兜底⽅法。 上边讲解了使⽤了blockHandler和fallback,其实更多的是异常⽅法的指定,其实我们也可以使⽤blockHandlerClass和fallbackClass来处理这样的情形(全局兜 底)。

  1. 创建⼀个资源⽅法

image-20230829151604097

  1. 书写⼀个全局blockException的处理逻辑

image-20230829151613806

  1. 书写⼀个全局处理其他异常的处理逻辑

image-20230829151631591

九、Sentinel 规则持久化

通过前⾯的讲解,我们已经知道,可以通过 Dashboard 来为每个 Sentinel 客户端设置各种各样的规则,但是这⾥有⼀个问题,就是这些规则默认是存放在内存中,极不稳定,所以需要将其持久化。

本地⽂件数据源会定时轮询⽂件的变更,读取规则。这样我们既可以在应⽤本地直接修改⽂件来更新规则,也可以通过 Sentinel 控制台推送规则。以本地⽂件数据源为例,推送过程如下图所示:

image-20230830201229055

书写持久化类

package com.dailyblue.java.study.cloud.config;
import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class FilePersistence implements InitFunc {
@Override
public void init() throws Exception {
//指定⽂件⽣成⽬录
 String applicationName = "具体微服务名称";
String ruleDir = System.getProperty("user.home") + "/sentinelRules/" +
applicationName;
String flowRulePath = ruleDir + "/flow-rule.json";
String degradeRulePath = ruleDir + "/degrade-rule.json";
String systemRulePath = ruleDir + "/system-rule.json";
String authorityRulePath =
ruleDir + "/authority-rule.json";
String paramFlowRulePath = ruleDir + "/param-flow-rule.json";
this.mkdirIfNotExits(ruleDir);
this.createFileIfNotExits(flowRulePath);
this.createFileIfNotExits(degradeRulePath);
this.createFileIfNotExits(systemRulePath);
this.createFileIfNotExits(authorityRulePath);
this.createFileIfNotExits(paramFlowRulePath);
// 流控规则
ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new
FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
FlowRuleManager.register2Property(flowRuleRDS.getProperty());
WritableDataSource<List<FlowRule>> flowRuleWDS = new
FileWritableDataSource<>(
flowRulePath,
this::encodeJson
 );
WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
// 降级规则
ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new
FileRefreshableDataSource<>(
degradeRulePath,
degradeRuleListParser
 );
DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
WritableDataSource<List<DegradeRule>> degradeRuleWDS = new
FileWritableDataSource<>(
degradeRulePath,
this::encodeJson
 );
WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
// 系统规则
ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new
FileRefreshableDataSource<>(
systemRulePath,
systemRuleListParser);
SystemRuleManager.register2Property(systemRuleRDS.getProperty());
WritableDataSource<List<SystemRule>> systemRuleWDS = new
FileWritableDataSource<>(
systemRulePath,
this::encodeJson);
WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
// 授权规则
ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new
FileRefreshableDataSource<>(
authorityRulePath,
authorityRuleListParser
 );
AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new
FileWritableDataSource<>(
authorityRulePath,
this::encodeJson
 );
WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
// 热点参数规则
ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new
FileRefreshableDataSource<>(
paramFlowRulePath,
paramFlowRuleListParser
 );
ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new
FileWritableDataSource<>(paramFlowRulePath,
this::encodeJson
 );
ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
 }
private Converter<String, List<FlowRule>> flowRuleListParser = source ->
JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
 });
private Converter<String, List<DegradeRule>> degradeRuleListParser = source
-> JSON.parseObject(
source,
new TypeReference<List<DegradeRule>>() {
 });
private Converter<String, List<SystemRule>> systemRuleListParser = source ->
JSON.parseObject(
source,
new TypeReference<List<SystemRule>>() {
 });
private Converter<String, List<AuthorityRule>> authorityRuleListParser =
source -> JSON.parseObject(
source,
new TypeReference<List<AuthorityRule>>() {
 });
private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser =
source -> JSON.parseObject(
source,
new TypeReference<List<ParamFlowRule>>() {
 });
private void mkdirIfNotExits(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
 }
 }
private void createFileIfNotExits(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
file.createNewFile();
 }
 }
private <T> String encodeJson(T t) {
return JSON.toJSONString(t);
 }
}

添加配置

在 resources 下创建配置⽬录 META-INF/services ,然后添加⽂件com.alibaba.csp.sentinel.init.InitFunc 。

image-20230830201503043

在⽂件中添加配置类的全路径

com.dailyblue.java.study.cloud.config.FilePersistence

十、Feign整合Sentinel

  1. 引⼊sentinel的依赖

    image-20230829151856506

  2. 在配置⽂件中开启Feign对Sentinel的⽀持

    image-20230829151906867

  3. 创建容错类

    image-20230829151914830

  4. 在业务上指定出错后调⽤的容错类

    image-20230829151928215

  5. 在启动类上引⼊feign⽀持
    image-20230829151935493

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值