1.为什么引入Sentinel
在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪。
在传统SpringCloud的微服务架构下,我们最常使用的是hystrix,《SpringCloud05—服务容错保护:Spring Cloud Hystrix
》后来随着Fegin的引入,我们又开始使用Fegin的容错和降级服务《SpringCloud06—声明式服务调用:Spring Cloud Feign
》,但是我们今天带来一个新的组件Sentinel,Sentinel 是阿里巴巴开源的一款断路器实现,本身在阿里内部已经被大规模采用,非常稳定。在讲解Sentinel之前,我们先看看常见的容错组件之间的差异
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离(并发线程数限流) | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间、异常比率、异常数 | 基于异常比率 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) |
动态规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 |
流量整形 | 支持预热模式、匀速器模式、预热排队模式 | 不支持 |
系统自适应保护 | 支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、查看秒级监控、机器发现等 | 简单的监控查看 |
2.服务雪崩
我们先来通过一个很简单的程序来看看服务雪崩
首先我们先准备一个压力测试小工具:jmeter
点击此处下载
使用方法也很简单:
-
1.修改配置,并启动软件
进入bin目录,修改jmeter.properties文件中的语言支持为language=zh_CN,然后点击jmeter.bat,启动软件。
-
2.添加线程组
-
3.配置线程并发数
-
4.添加Http取样
-
5.配置取样,并启动测试
-
6.修改服务的并发配置
# 配置tomcat的最大并发数,默认200 server.tomcat.threads.max=10
-
7.启动测试,同时用浏览器访问message接口
controller如下:
@RequestMapping("/order/message")
public Map<String, Object> getMessage() {
Map<String, Object> map = new HashMap<>();
map.put("code", 20000);
map.put("msg", "高并发下的测试问题");
return map;
}
此时我们会发现由于order方法囤积了大量请求, 导致message方法的访问出现了问题,这就是服务雪崩的雏形。
在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。
由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩效应” 。
服务雪崩产生的流程如下所示:
雪崩发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某台机器的资源耗尽。我们无法完全杜绝雪崩源头的发生,只有做好足够的容错,保证在一个服务发生问题,不会影响到其它服务的正常运行。也就是"雪落而不雪崩"。
3.常见容错方案
3.1 隔离
它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。常见的隔离方式有:线程池隔离和信号量隔离
3.2 超时
在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。
3.3 限流
限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。
《Redis限流——滑动窗口限流》
3.4 熔断
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
服务熔断一般有三种状态:
- 熔断关闭状态(Closed)
服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制 - 熔断开启状态(Open)
后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法 - 半熔断状态(Half-Open)
尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
3.5 降级
降级其实就是为服务提供一个托底方案,一旦服务无法正常调用,就使用托底方案
4.Sentinel入门
4.1 什么是Sentinel
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 等应用容器。
4.2 微服务集成Sentinel
1.添加mavel依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.13</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
</dependencies>
</project>
2.安装Sentinel控制台
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。
进入cmd,使用指令启动
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.3.jar
参数解释:
- -Dserver.port=8090 控制台端口
- -Dcsp.sentinel.dashboard.server=localhost:8090 控制台的地址,指定控制台后客户端会自动向该地址发送心跳包
- -Dproject.name=sentinel-dashboard 指定Sentinel控制台程序的名称
3.修改我们项目的配置
# 配置sentinel
#跟控制台交流的端口,随意指定一个未使用的端口即可
spring.cloud.sentinel.transport.port=9999
# 指定控制台服务的地址
spring.cloud.sentinel.transport.dashboard=localhost:8090
- 4.通过浏览器访问地址:http://localhost:8090/
用户名密码均是sentinel
注意:如果没有的话可以尝试先随便访问一个接口,如本项目上面演示服务雪崩的接口:http://localhost:8080/order/message,然后在刷新Sentinel控制台页面
Sentinel的控制台其实就是一个SpringBoot编写的程序。我们需要将我们的微服务程序注册到控制台上,即在微服务中指定控制台的地址, 并且还要开启一个跟控制台传递数据的端口, 控制台也可以通过此端口调用微服务中的监控程序获取微服务的各种信息。
接下来我们通过sentinel实现一个接口的限流
4.3.实现一个接口的限流
我们继续上面的message接口进行测试限流
在浏览器端快速刷新http://localhost:8080/order/message页面,我们将会看到以下页面:
5. Sentinel的概念和功能
5.1 基本概念
- 资源
资源就是Sentinel要保护的东西
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,可以是一个服务,也可以是一个方法,甚至可以是一段代码。
什么意思呢?
就像我们刚刚使用的接口message方法,就可以认为是一个资源 - 规则
规则就是用来定义如何进行保护资源的
作用在资源之上, 定义以什么样的方式保护资源,主要包括流量控制规则、熔断降级规则以及系统保护规则。
就比如我们对message进行限流就是一种规则
5.2 重要功能
Sentinel的主要功能就是容错,主要体现为下面这三个:
流量控制
流量控制在网络传输中是一个常用的概念,它用于调整网络包的数据。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状。
熔断降级
当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
Sentinel 对这个问题采取了两种手段:
- 通过并发线程数进行限制
Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。 - 通过响应时间对资源进行降级
除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。
当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。
Sentinel 和 Hystrix 的区别
两者的原则是一致的, 都是当一个资源出现问题时, 让其快速失败, 不要波及到其它服务但是在限制的手段上, 确采取了完全不一样的方法:
- Hystrix 采用的是线程池隔离的方式, 优点是做到了资源之间的隔离, 缺点是增加了线程切换的成本。
- Sentinel 采用的是通过并发线程的数量和响应时间来对资源做限制。
系统负载保护
Sentinel 同时提供系统维度的自适应保护能力。当系统负载较高的时候,如果还持续让请求进入可能会导致系统崩溃,无法响应。在集群环境下,会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。
我们了解这么多只是对其工作原理有个基本了解,那么我们开发者需要干嘛呢,我们只需要在Sentinel的资源上配置各种各样的规则,来实现各种容错的功能。
6.Sentinel规则配置实战
6.1 流控规则
流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
我们先创建一个接口
@RequestMapping("/order/message1")
public Map<String, Object> getMessage_1() {
Map<String, Object> map = new HashMap<>();
map.put("code", 20000);
map.put("msg", "流控规则测试");
return map;
}
流量控制最基本的就是QPS,即每秒访问的次数
上图的配置则表示接口message1一旦每秒的请求达到三次以上就会进行限流
同时我们还可以看到有并发线程数,这个也很好理解,就是指每次访问的线程数量不能超过单击阈值,一旦超过就会禁止访问。
再往下接着我们能见到其显示的流控模式,流控模式有三种,我大致说一下这三种都分别有什么作用 :
- 直接(默认):接口达到限流条件时,开启限流
- 关联:当关联的资源达到限流条件时,开启限流 [适合做应用让步]
- 链路:当从某个接口过来的资源达到限流条件时,开启限流
直接模式我们之前都见过效果,我们看看关联和链路模式
6.1.1 关联模式
关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流
我们在创建一个接口 message1_asssociate
@RequestMapping("/order/message1_asssociate")
public Map<String, Object> message1_asssociate() {
Map<String, Object> map = new HashMap<>();
map.put("code", 20000);
map.put("msg", "getMessage_1的关联接口");
return map;
}
我们继续使用压力测试工具jmeter对接口message1_asssociate进行测试
我们使用浏览器会发现接口message1已经被限流
除此之外我们可以看到我们的流控设置中还有
他们分别都有什么样的含义呢?
6.1.2 配置流控效果
- 快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果
- Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。
- 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。
6.2 降级规则
降级规则就是设置当满足什么条件的时候,对服务进行降级。
目前Sentinel提供了三个衡量条件:
我们以上图的设置为例对这三个策略进行解释:
- 慢调用比例
当资源的平均响应时间超过阈值(以 ms 为单位)之后,资源进入准降级状态。如果接下来 1s 内持续进入 5 个请求,它们的 RT都持续超过这个阈值,那么在接下的时间窗口(以 s 为单位)之内,就会对这个方法进行服务降级。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
- 异常比例
当资源的每秒异常总数占通过量的比值超过阈值之后,资源进入降级状态,即在接下的时间窗口(以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0,1.0]。
我们具体以一个实际代码作为演示:
int i = 0;
@RequestMapping("/order/message3")
public Map<String, Object> message3() {
Map<String, Object> map = new HashMap<>();
i++;
if (i % 3 == 0) {
throw new RuntimeException("异常比例");
}
map.put("code", 20000);
map.put("msg", "异常比例");
return map;
}
在控制台设置异常比例
使用jmter开启大于5个线程进行访问
我们在浏览器进行访问
- 异常数
当资源近 1 分钟的异常数目超过阈值之后会进行服务降级。注意由于统计时间窗口是分钟级别的,若时间窗口小于 60s,则结束熔断状态后仍可能再进入熔断状态。
在上面的设置中 ,我们可能观察到流控规则和降级规则显示的内容是一样的,我们如何进行区分呢?
6.3 热点规则
热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。
接下来我们分别尝试连续快速访问:
http://localhost:8080/order/message4?name=ninesun
http://localhost:8080/order/message4?age=12
可以看到访问第一个元素的链接已经被熔断
6.4 授权规则
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:
- 白名单:请求来源位于白名单才放行
- 黑名单:请求来源于黑名单时不通过,其他的请求一律放行
@RequestMapping("/order/message5")
public Map<String, Object> message5() {
Map<String, Object> map = new HashMap<>();
map.put("code", 20000);
map.put("msg", "授权规则");
return map;
}
自定义来源处理规则
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String serviceName = httpServletRequest.getParameter("serviceName");
return serviceName;
}
}
授权规则配置
这个配置的意思是只有serviceName=android不能访问(黑名单)
我们进行测试
访问:http://localhost:8080/order/message5?serviceName=android
我们可以看到这个链接已经无法访问
6.5 自定义返回异常
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
@Component
public class ExceptionHandlerPage implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
httpServletResponse.setContentType("application/json;charset=utf-8");
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("code", 500);
if (e instanceof FlowException) {
resultMap.put("message", "接口被限流了");
resultMap.put("data", -1);
} else if (e instanceof DegradeException) {
resultMap.put("message", "接口被降级了");
resultMap.put("data", -2);
}
httpServletResponse.getWriter().write(JSON.toJSONString(resultMap));
}
}
我们回到之前的测试接口,再次测试就会发现已经有比较友好的提示了
7.Sentinel规则持久化
我们在不停的重启项目之后会发现我们之前配置的规则都会莫名其妙没了,这是因为我们的规则保存在内存里,这就导致每次重启使得之前的配置就消失了,所以我们需要将规则持久化
本地文件数据源会定时轮询文件的变更,读取规则。这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。
添加持久化配置
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 DataSourceInitFunc implements InitFunc {
@Override
public void init() throws Exception {
// 持久化在本地的目录,如果你对这个路径不喜欢,可修改为你喜欢的路径
String ruleDir = System.getProperty("user.home") + "\\sentinel\\order\\rules";
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
// 这样当规则文件发生变化时,就会更新规则到内存
FlowRuleManager.register2Property(flowRuleRDS.getProperty());
WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
flowRulePath,
this::encodeJson
);
// 将可写数据源注册至transport模块的WritableDataSourceRegistry中
// 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
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<>(
flowRulePath,
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);
}
}
- 1.在resources目录下新建目录:META-INF
- 2.在META-INF目录下新建目录services
- 3.在services目录下新建文件,文件名为:com.alibaba.csp.sentinel.init.InitFunc
- 4.在刚刚新建好的文件里添加以下内容:
com.example.sentinel.config.DataSourceInitFunc
这个内容来自于哪儿呢?
来自于你配置文件的相对路径
在application.properties文件中添加以下配置
# 取消控制台懒加载
spring.cloud.sentinel.eager=true
# 配置sentinel日志
## 默认值${home}/logs/csp/
spring.cloud.sentinel.log.dir=./logs
# 日志带上线程id
spring.cloud.sentinel.log.switch-pid=true
接下来我们重启服务,可以在我们本机的以下目录看到:
同时即使我们重启项目也可以看到我们的规则仍然保留着
当然我们还有更高级的《sentinel规则持久化到nacos》