文章目录
Sentinel–服务容错
一、⾼并发带来的问题
在微服务架构中,我们将业务拆分成⼀个个的服务,服务与服务之间可以 相互调⽤,但是由于⽹络原因或者⾃身的原因,服务并不能保证服务的100%可 ⽤,如果单个服务出现问题,调⽤这个服务就会出现⽹络延迟,此时若有⼤量的⽹络涌⼊,会形成任务堆积,最终导致服务瘫痪。
二、⾼并发问题案例演示
前期准备
启动nacos服务
⼀.创建⼀个服务提供者项⽬,在controller书写两个⽅法供消费者调⽤,⼀个⽅法被延迟,另⼀个⽅法正常。
搭建项目
导入依赖
<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包
@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书写两个⽅法调⽤服务提供者的⽅法,⼀个会阻塞,⼀个正常。
搭建项目
导入依赖
<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包
@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⾏左右)
3.启动jmeter.bat⽂件
4.添加线程组
自动跳出
5.配置线程并发数
6.添加HTTP取样
7.配置取样,并启动测试
8.访问正常的请求url查看效果
9.大量的请求进来
10.请注意,测试完关闭
结论:
此时会发现,由于a⽅法囤积了⼤量请求,导致b⽅法的访问出现了问题, 这就是服务雪崩的雏形。
三、服务雪崩效应
在分布式系统中,由于⽹络原因或⾃身的原因,服务⼀般⽆法保证100%可 ⽤。如果⼀个服务出现了问题,调⽤这个服务就会出现线程阻塞的情况,此时 若有⼤量的请求涌⼊,就会出现多条线程阻塞等待,进⽽导致服务瘫痪。 由于服务于服务之间的依赖性,故障会传播,会对整个微服务系统造成灾 难性的严重后果,这就是服务故障的“雪崩”效应。
雪崩发⽣的原因多种多样,有不合理的容量设计,或者是⾼并发下某⼀个⽅法 响应变慢,亦或是某台机器的资源耗尽。我们⽆法完全杜绝雪崩源头的发⽣, 只有做好⾜够的容错,保证在⼀个服务发⽣问题,不会影响到其他服务的正常 运⾏。也就是“雪落⽽不雪崩”。
常⻅容错⽅案
要防⽌雪崩的扩散,我们就要做好服务的容错,容错说⽩了就是保护⾃⼰ 不被猪队友拖垮的⼀些措施,下⾯介绍常⻅的服务容错思路和组件。 常⻅的容错思路有隔离、超时、限流、熔断、降级这⼏种,下⾯分别介绍⼀下。
-
隔离
它是指将系统按照⼀定的原则划分为若⼲服务模块,各个模块之间相对独 ⽴,⽆强影响。当有故障发⽣时,能将问题和影响隔离在某个模块内部, ⽽不扩散⻛险,不波及其他模块,不影响整体的系统服务。常⻅的隔离⽅ 式有:线程池隔离和信号量隔离。
-
超时
在上游(A服务)服务调⽤下游(B服务)服务的时候,设置⼀个最⼤响应 时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。
-
限流
限流就是限制系统的输⼊和输出流量已达到保护系统的⽬的。为了保证系 统的稳固运⾏,⼀旦达到的需要限制的阈值,就需要限制流量并采取少量 措施以完成限制流量的⽬的。
-
熔断
在互联⽹系统中,当下游(B服务)服务因访问压⼒过⼤⽽响应变慢或失 败,上游(A服务)服务为了保护系统整体的可⽤性,可以暂时切断对下 游服务的调⽤。这种牺牲局部,保全整体的措施就叫做熔断。
服务熔断⼀般有三种状态:
a. 熔断关闭状态(Closed)
B服务没有故障时,熔断器所处的状态,对调⽤⽅(A服务)的调⽤ 不做任何限制。
b. 熔断开启状态(Open)
B服务有故障时,后续对该服务接⼝的调⽤不再经过⽹络(不在对B 服务进⾏访问),直接执⾏本地的fallback的⽅法。
c. 半熔断状态(Half-Open)
尝试恢复服务调⽤,允许有限的流量调⽤该服务,并监控调⽤成功 率。如果成功率达到预期,则说明服务已恢复,进⼊熔断关闭状态; 如果成功率仍旧很低,则重新进⼊熔断开启状态。
-
降级
降级其实就是为服务提供⼀个托底(备选)⽅案,⼀旦服务⽆法正常调 ⽤,就使⽤托底(备选)⽅案。
四、常⽤的容错组件
- Hystrix:由NetFlix开源的⼀个延迟和容错库,⽤于隔离访问远程系统、 服务或者第三⽅库,防治级联失败,从⽽提升系统的可⽤性与容错性。
- Resilience4J:是⼀款⾮常轻量、简单,并且⽂档⾮常清晰、丰富的熔断 ⼯具,这也是Hystrix官⽅推荐的替代产品。不仅如此,Resilience4J还原 ⽣⽀持SpringBoot1.x/2.x,⽽且监控也⽀持和prometheus等多款主流产品 进⾏整合。
- Sentinel:是阿⾥巴巴开源的⼀款断路器实现,本身在阿⾥内部已经被⼤规模采⽤,⾮常稳定。
五、Sentinel⼊⻔
1、什么是Sentinel
Sentinel(分布式系统的流量防卫兵)是阿⾥开源的⼀套⽤于“服务容错”的综合性解决⽅案,它以流量为切⼊点,从流量控制、熔断降级、系统负载保护等 多个维度来保护服务的稳定性。
官⽅⽹站:https://github.com/alibaba/Sentinel/
Sentinel具有以下特征:
- 丰富的应⽤场景:Sentinel承接了阿⾥巴巴近10年的双⼗⼀⼤促流量的核 ⼼场景,例如秒杀(突发流量控制在系统容量可以承受的范围)、消息 削峰填⾕、集群流量控制、实时熔断下游不可⽤应⽤等。
- 完备的实时监控:Sentinel提供了实时的监控功能。通过控制台可以看到 接⼊应⽤的单台机器秒级数据,甚⾄500台以下规模的集群的汇总运⾏情 况。
- ⼴泛的开源⽣态:Sentinel提供开箱即⽤与其他开源框架/库的整合模 块,例如Spring Cloud、Dubbo、gRPC的整合。只需要引⼊相应的依赖并 进⾏简单的配置即可快速地接⼊Sentinel。
- 完善的SPI扩展点:Sentinel提供简单易⽤、完善的SPI扩展接⼝,你可以 通过实现扩展接⼝来快速地定制逻辑。例如定制规则管理、适配动态数 据源等。
Sentinel分为两个部分:
- 核⼼库(Java客户端)不依赖任何框架/库,能够运⾏于所有Java运⾏环 境,同时对Dubbo/Spring Cloud等框架也有较好的⽀持。
- 控制台(Dashboard)基于Spring Boot开发,打包后可以直接运⾏,不需 要额外的Tomcat等应⽤容器。
2、微服务集成Sentinel
为微服务集成Sentinel⾮常简单,只需要加⼊Sentinel的依赖就⾏。本次演示代码 都集中在消费端,sentinel在正常使⽤中可以添加到服务提供者或者服务消费者 的任意模块中。
- 在消费者的pom.xml中引⼊相关依赖
- 编写⼀个controller测试使⽤
3、安装Sentinel控制台
Sentinel提供⼀个轻量级的控制台,它提供机器发现、单机资源实时监控以 及规则管理等功能。
- 下载jar包,存放到任意⽂件夹 https://github.com/alibaba/Sentinel/releases (用迅雷下载)
- 通过cmd命令启动控制台(指定端口号启动,默认是8080,避免端口冲突)
java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888-Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
3.修改“消费者项⽬”,在⾥边加⼊有关控制台的配置
spring:
sentinel:
transport:
port: 8719
dashboard: localhost:8888
-
打开浏览器输⼊以下⽹址,默认⽤户名密码都是sentinel
https://localhost:8080
注意事项:
- 需要⾸先启动Nacos服务端后才可使⽤
- Sentinel是懒加载模式,消费者启动后不会实时被Sentinel监控,需访问⼀ 次后才可看到。
4、⼊⻔体验----实现⼀个接⼝的限流
- 通过控制台为/customer/b请求添加⼀个流控规则
QPS每秒查询率(Query Per Second) 是对⼀个特定的查询服务器在规定时 间内所处理流量多少的衡量标准,在因特⽹上,作为域名系统服务器的 机器的性能经常⽤每秒查询率来衡量,即每秒的响应请求数,也即是最 ⼤吞吐能⼒。
- 通过浏览器快速频繁访问,观察效果
六、Sentinel的概念和功能
1、基本概念
-
资源:是Sentinel的关键概念。它可以是Java应⽤程序中的任何内容,可以是⼀个服务,也可以是⼀个⽅法,甚⾄可以是⼀段代码。就是Sentinel 需要保护的东⻄。
⼊⻔案例中的customer/b⽅法就可以认为是⼀个资源
-
规则:作⽤在资源之上,定义以什么样的⽅式保护资源,主要包括流量 控制规则、熔断降级规则以及系统保护规则。规则就是⽤来定义如何进 ⾏保护资源的。
⼊⻔案例就是为customer/b资源设置了⼀种流控规则,限制了进⼊ customer/b的流量
2、重要功能
Sentinel的主要功能就是容错,主要体现为下⾯这三个:
-
流量控制:在⽹络传输中是⼀个常⽤的概念,它⽤于调整⽹络包的数 据。任意时间到来的请求往往是随机不可控的,⽽系统的处理能⼒是有 限的。我们需要根据系统的处理能⼒对流量进⾏控制。Sentinel可以根据 需要把随机的请求(数)调整成合适的形状(⼀定的请求数)。
⽬的 :保证⾃⼰不被上游服务压垮。
-
熔断降级:当检测到调⽤链路中某个资源出现不稳定的表现,例如请求 响应时间⻓或异常⽐例升⾼的时候,则对这个资源的调⽤进⾏限制,让 请求快速失败,避免影响到其它的资源⽽导致级联故障。
⽬的:保证⾃ ⼰不被下游服务拖垮。
Sentinel 对这个问题采取了两种⼿段:
通过并发线程数进⾏限制:
和资源池隔离的⽅法不同,Sentinel 通过限制 资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没 有线程切换的损耗,也不需要您预先分配线程池的⼤⼩。当某个资源出现 不稳定的情况下,例如响应时间变⻓,对资源的直接影响就是会造成线程 数的逐步堆积。当线程数在特定资源上堆积到⼀定的数量之后,对该资源 的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
通过响应时间对资源进⾏降级:
除了对并发线程数进⾏控制以外, Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出 现响应时间过⻓后,所有对该资源的访问都会被直接拒绝,直到过了指定 的时间窗⼝之后才重新恢复。
-
系统负载保护:当系统负载较⾼的时候,如果还持续让请求进⼊可能会 导致系统崩溃,⽆法响应。在集群环境下,会把本应这台机器承载的流 量转发到其它的机器上去。如果这个时候其它的机器也处在⼀个边缘状 态的时候,Sentinel 提供了对应的保护机制,让系统的⼊⼝流量和系统的 负载达到⼀个平衡,保证系统在能⼒范围之内处理最多的请求。
⽬的:保证外界环境良好(CPU、内存)。
总之⼀句话:我们需要做的事情,就是在Sentinel的资源上配置各种各样的规 则,来实现各种容错的功能。
七、Sentinel规则
1、流控规则
流控控制,其原理是监控应⽤流量的QPS(每秒查询率)或并发线程数等指标,当达到指定的阈(yu)值时对流量进⾏控制,以避免被瞬时的流量⾼峰冲垮,从⽽保障应⽤的⾼可⽤性。
- 资源名:唯⼀名称。默认请求路径
- 针对来源:Sentinel可以针对调⽤者进⾏限流,填写微服务名,默认 default (不区分来源)
- 阈值类型/单机阈值
- QPS(每秒钟的请求数量):当调⽤该api的QPS达到阈值的时候, 进⾏限流。
- 线程数:当调⽤该api的线程数达到阈值的时候,进⾏限流。(可以 使⽤jMeter模拟多线程)
- 是否集群:不需要集群
- 流控模式:
- 直接(默认):当前请求达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流⾃⼰,⼀般适合做应⽤让步
3.链路:只记录指定链路上的流量(指定资源从⼊⼝资源进来的流量,如果达到阈值,就进⾏限流),可看作api级别的针对来源,链路的粒度更 细,需要如下步骤才能实现
1.创建service下的实现类,写⼊具体⽅法
2.在Sentinel控制台添加链路设置
3.在yml⽂件中设置链路开启(2.1.1版本后才能使⽤)
流控效果:
- 快速失败:直接失败,抛异常,不做任何额外的处理,是最简单 的效果。
- Warm up(预热):它从开始阈值到最⼤QPS阈值会有⼀个缓冲阶 段,⼀开始的阈值是最⼤QPS阈值的1/3,然后慢慢增⻓,直到最 ⼤阈值,适⽤于将突然增⼤的流量转换为缓步增⻓的场景。
- 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数 量,其余的排队等待;它还会让设置⼀个超时时间,当请求超过时间还未处理,则会被丢弃。
2、降级规则
降级规则就是设置当满⾜什么条件的时候,对服务进⾏降级。Sentinel提供了三 个衡量条件:
- 慢调⽤⽐例:当资源的响应时间超过最⼤RT(以ms为单位,最⼤RT即最 ⼤响应时间)之后,资源进⼊准降级状态。如果接下来1ms内持续进⼊5 个请求(最⼩请求数),他们的RT都持续超过这个阈值,那么在接下的 熔断时⻓(以s为单位)之内,就会对这个⽅法进⾏服务降级。
- 异常⽐例:当资源的每秒异常总数占通过量的⽐值数超过阈值之后,资 源进⼊降级状态,即在接下来的熔断时⻓之内,对这个⽅法的调⽤都会 ⾃动地返回。异常⽐率的阈值范围是[0.0,1.0]。
- 异常数:当资源近统计时⻓的异常数⽬超过阈值(异常数)之后会进⾏服务降级。
3、热点规则
热点参数流控规则是⼀种更细粒度的流控规则,它允许将规则具体到参数上。
- 编写具体代码
- 配置热点规则
- 配置⾼级规则
热点规则相⽐较前⼏种,使⽤较少,处理的为形式参数的问题,甚⾄于更 细分到参数值的阈值。
4、授权规则
很多时候,我们需要根据调⽤来源来限制资源是否通过,这时候可以使⽤ Sentinel的⿊⽩名单的功能,⿊⽩名单根据资源的请求来源(origin)限制资源 是否通过。
- 若配置⽩名单则只有请求来源位于⽩名单内时才可通过。
- 若配置⿊名单则请求来源位于⿊名单时不通过,其余的请求通过。
实现步骤:
- 创建⼀个类,实现接⼝RequestOriginParser,重写⽅法
- 在Sentinel控制台中进⾏授权规则设置
授权规则,根据匹配参数⾥⾯的参数的类型是否匹配参数条件来进⾏限制访问。
5、系统规则
系统保护规则是从应⽤级别的⼊⼝流量进⾏控制,从单台机器的总体Load、 RT、⼊⼝QPS、CPU使⽤率和线程数五个维度监控应⽤数据,让系统尽可能跑在 最⼤吞吐量的同时保证系统整体的稳定性。这个规则和前边四个规则最⼤的区 别在于系统规则是从应⽤级别⼊⼿,⽽其他规则是从资源收⼊的。
- LOAD:只有在 Linux 系统的机器上才会⽣效,可以根据当前操作系统的 负载,来决定是否触发保护(把请求拒绝掉);
- RT(响应时间):当单台机器上所有⼊⼝流量的平均RT达到阈值即触发 系统保护,单位是毫秒;
- 线程数:当单台机器上所有的请求消耗的线程数加起来,如果超过某个 值,就停⽌新的请求;
- ⼊⼝ QPS:当单台机器上所有接⼝的 QPS 加起来,如果超过某个值,就 停⽌新的请求;
- CPU 使⽤率:当单台机器上所有⼊⼝流量的CPU 的使⽤率,如果超过⼀ 个百分⽐,就停⽌新的请求;
⼀般情况下,系统规则使⽤很少,⼀般是在运维中使⽤⽐较多⼀些。
6、自定义异常返回
通过⾃定义异常返回,可以根据限流类型返回特定内容的⻚⾯。
- 创建⼀个类,实现BlockExceptionHandler接⼝
- 重写handle⽅法
- 再次刷新限流⻚⾯
八、@SentinelResource的使⽤
Sentinel 提供了 @SentinelResource 注解⽤于定义资源,并提供了AspectJ的扩展 ⽤于⾃动定义资源、处理BlockException、其他异常情况等。
- 定义了资源
- 定义当资源内部发⽣异常的时候的处理逻辑
常⻅属性
这⾥我们着重讲解当发⽣异常后处理逻辑
- 创建⼀个资源定义⽅法
- 书写处理blockException的处理逻辑
- 书写处理其他异常的处理逻辑(兜底⽅法)
实际开发当中经常出现,服务限流,但是超出规则的默认返回提示,这样不太 符合业务逻辑。可以使⽤blockHandler 来指定⼀个出现异常的兜底⽅法。 上边讲解了使⽤了blockHandler和fallback,其实更多的是异常⽅法的指定,其实我们也可以使⽤blockHandlerClass和fallbackClass来处理这样的情形(全局兜 底)。
- 创建⼀个资源⽅法
- 书写⼀个全局blockException的处理逻辑
- 书写⼀个全局处理其他异常的处理逻辑
九、Sentinel 规则持久化
通过前⾯的讲解,我们已经知道,可以通过 Dashboard 来为每个 Sentinel 客户端设置各种各样的规则,但是这⾥有⼀个问题,就是这些规则默认是存放在内存中,极不稳定,所以需要将其持久化。
本地⽂件数据源会定时轮询⽂件的变更,读取规则。这样我们既可以在应⽤本地直接修改⽂件来更新规则,也可以通过 Sentinel 控制台推送规则。以本地⽂件数据源为例,推送过程如下图所示:
书写持久化类
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 。
在⽂件中添加配置类的全路径
com.dailyblue.java.study.cloud.config.FilePersistence
十、Feign整合Sentinel
-
引⼊sentinel的依赖
-
在配置⽂件中开启Feign对Sentinel的⽀持
-
创建容错类
-
在业务上指定出错后调⽤的容错类
-
在启动类上引⼊feign⽀持