关于springcloud:吃透微服务-服务容错之Sentinel

56次阅读

共计 14009 个字符,预计需要花费 36 分钟才能阅读完成。

大家好,我是小菜。
一个心愿可能成为 吹着牛 X 谈架构 的男人!如果你也想成为我想成为的人,不然点个关注做个伴,让小菜不再孤独!

本文次要介绍 SpringCloud 中 Sentinel

如有须要,能够参考

如有帮忙,不忘 点赞

微信公众号已开启,小菜良记,没关注的同学们记得关注哦!

上篇咱们曾经理解到微服务中重要的组件之一 — 服务网关 Gateway。咱们在取精排糠的同时,不可否认微服务给咱们带来的益处。其中承载高并发的益处更是让各大公司趋之若鹜!

然而想要接管高并发,天然要接管它带来的一系列问题。在微服务架构中,咱们将业务拆分成了一个个服务,这样的益处之一便是分担压力,一个服务顶不住了,下一个服务顶上去。然而服务与服务之间能够互相调用,因为网络起因或本身的起因,服务并不能保障百分百可用,也就是各大公司当初追寻的几个 9(99.99%,99.999%)可用!如果单个服务呈现问题,调用这个服务就会呈现网络提早,此时如果正好有大量的网络涌入,势必会造成工作沉积,导致服务瘫痪!

空口无凭,小菜给你整个示例:

OrderController

这里咱们通过接口模仿了下单的场景,其中通过线程休眠的形式模仿了网络提早的场景。接下来咱们还须要改一下 tomcat 中并发的线程数

applicatio.yaml

server:
  tomcat:
    max-threads: 10  # 默认的并发数为 200

当这所有准备就绪好,咱们这个时候还须要压测工具 Jmeter 的帮忙(不会操作的同学具体看以下应用)

  1. 首先关上 Jmeter 软件,抉择新建线程组

  1. 设置申请线程数

  1. 设置 HTTP 申请取样器

  1. 设置申请的接口

实现下面步骤就能够点击开始了。不过测试之前咱们确保两个 API 都是能够拜访的:

而后开始压力测试,当大量申请发送到创立订单的接口时,咱们这时候通过网页拜访 detail API 发现申请始终在阻塞,过一会才联通!

这无疑是一个开发炸弹,而这便是高并发带来的问题。看到这里,祝贺你胜利见证了一场服务雪崩的问题。那无妨带着这份趣味持续往下看,会给你惊喜的。

Sentinel

一、服务雪崩

咱们结尾间接用服务雪崩勾引你,不晓得你心动了没有,如果不想你的我的项目在线上环境面临同样的问题,连忙为我的项目搭线起来,不经意的行动往往能让你升职加薪!

在分布式系统中,因为网络起因或本身的起因。服务个别无奈保障 100% 可用,如果一个服务呈现了问题,调用这个服务就会呈现线程阻塞的状况,此时若有大量的申请涌入,就会呈现多条线程阻塞期待,进而导致服务瘫痪。而因为服务与服务之间的依赖性,故障会进行流传,相互影响之下,会对整个微服务零碎造成灾难性的严重后果,这就是服务故障的 “雪崩效应”

最开始的时候,服务A~C 三个服务其乐融融的互相调用,响应也很快,为主人工作也很卖命

好景不长,客人火了,并发量上来了。可能因为服务 C 还不够强壮的起因,服务 C 在某一天宕机了,然而服务 B 还是依赖服务 C,不停的进行服务调用

这个时候可能大家都还没意识到问题的严重性,只是狐疑可能申请太多了,导致服务器变卡了。申请持续发送,服务 A 这个时候也未知问题,一边感觉奇怪服务 B 是不是偷懒了,怎么还不把响应返回给它,一边持续发送申请。然而这个时候申请都在服务 B 沉积着,终于有一天服务 B 也累出问题了

这个时候人们开始埋怨服务 A 了,却不晓得服务 A 底层原来还依赖服务 B 和服务 C,而这时服务 B 和服务 C 都挂了。服务 A 这时才想通为什么服务 B 之前那么久没返回响应,原来服务 B 也依赖服务 C 啊!然而这个时候曾经晚了,申请一直接管,一直沉积,下场都是惊人的类似,也走向了宕机的后果。不过有一点不同的是,服务 A 宕机后须要承载了用户各种的骂声~

可悲的故事警觉了咱们,微服务架构之间并没有那么牢靠。有时候真的是说挂就挂,起因各种各样,不合理的容量设计,高并发状况下某个办法响应变慢,亦或是某台机器的资源耗尽。咱们如果不采取措施,只能坐以待毙,一直的在重启服务器中循环。然而咱们可能无奈杜绝雪崩的源头,然而如果咱们在问题产生后做好容错的筹备,保障下一个服务产生问题,不会影响到其余服务的失常运行,各个服务自扫家门雪,做到独立,雪落而不雪崩

二、容错计划

想要避免雪崩的扩散,就要做好服务的容错,容错说白了就是爱护本人不被其余队友坑,带进送人头的行列!那咱们有哪些容错的思路呢?

1)隔离计划

它是指将零碎依照肯定的准则划分为若干个服务模块,各个模块之间互相独立,无强依赖。当有故障产生时,能将问题和影响隔离在某个模块外部,而不扩散危险,不波及其余模块,不影响整体的零碎服务。常见的隔离形式有:线程隔离 和信号量隔离:

2)超时计划

在上游服务调用上游服务的时候,设置一个最大响应工夫,如果超过这个工夫上游服务还没响应,那么就断开连接,开释掉线程

3)限流计划

限流就是限度零碎的输出和输入流量已达到爱护零碎的目标。为了保证系统的巩固运行,一旦达到须要限度的阈值,就须要限度流量并采纳大量措施实现限度流量的目标

限流策略有很多,前期也会思考出一篇专门将如何进行限流

4)熔断计划

在互联网零碎中,当上游服务因拜访压力过大而相应变慢或失败的时候,上游服务为了爱护零碎整体的可用性,能够临时切断对上游服务的调用。这种就义部分,顾全整体的措施就叫做熔断

其中熔断有分为三种状态:

  • 熔断敞开状态(Closed)

服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限度

  • 熔断开启状态(Open)

后续对该服务接口的调用不再通过网络,间接执行本地的 fallback 办法

  • 半熔断状态(Half-Open)

尝试复原服务调用,容许无限的流量调用该服务,并监控成功率。如果成功率达到预期,则阐明服务曾经复原,进入熔断敞开状态;如果成功率仍然很低,则从新进入熔断敞开状态

5)降级计划

降级其实就是为服务提供一个 B 打算,一旦服务无奈失常,就启用 B 打算

计划其实有很多,然而很难说明那种计划是最好的。在开发者的世界中,没有最好,只有最适宜。那如果本人写一个容错计划往往是比拟容易出错的(功力浅近者除外),那么为了解决这个问题,咱们无妨用第三方曾经为我实现好的组件!

三、容错组件

1)Hystrix

Hystrix 是 Netflix 开源的一个提早和容错库,用于隔离拜访近程零碎,服务或者第三方库,避免级联失败,从而晋升零碎的可用性和容错性

2)Resilience4J

Resilience4J是一款十分轻量,简略,并且文档十分清晰,丰盛的熔断工具,这是 Hystrix 官网举荐的替代品。它反对 SpringBoot 1.x/2.x 版本,而且监控也反对和 prometheus 等多款主流产品进行整合

3)Sentinel

Sentinel 是阿里开源的一款断路器的实现,在阿里巴巴外部也曾经大规模采纳,能够说是十分稳固

不同之处

容错组件其实有很多,但各有风骚,上面别离阐明这这三种组件的不同之处,如何抉择,认真斟酌!

性能 Sentinel Hystrix resilience4j
隔离策略 信号量隔离(并发线程数限流) 线程池隔离 / 信号量隔离 信号量隔离
熔断降级策略 基于响应工夫,异样比率,异样数 基于异样比率 基于异样比率,响应工夫
实时统计实现 工夫滑动窗口(LeapArray) 工夫滑动窗口(基于 Rxjava) Ring Bit Buffer
动静规定配置 反对多种数据源 反对多种数据源 无限反对
扩展性 多个扩大点 插件的模式 接口的模式
基于注解的反对 反对 反对 反对
限流 基于 QPS,反对基于调用关系的限流 无限的反对 Rate LImiter
流量整形 反对预热模式,匀速器模式,预热排队模式 不反对 简略的 Rate Limiter 模式
零碎自适应爱护 反对 不反对 不反对
控制台 提供即用的控制台,可配置规定,查看秒级监控,机器发现等 简略的监控查看 不提供控制台,可对接其余监控零碎

之前有说过,一个新秀想让大伙承受并宽泛应用,必定得具备良好的个性能力冲出老牌的包围圈。那么 Sentinel 作为一个微服务中的新秀,只有具备让人称心的性能,能力被大伙承受。因而,这篇的配角便是 Sentinel,无妨深刻理解一番!

四、意识 Sentinel

学会用一个组件之前,咱们先须要晓得这个组件是什么。

1)什么是 Sentinel

Sentinel(分布式系统的流量防守兵)是阿里开源的一套用于 服务容错 的综合性解决方案。它以流量为切入点,从 流量管制 熔断降级 零碎负载爱护 等多个维度来爱护服务的稳定性。

2)个性

  • 丰盛的利用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促的流量的外围场景。在秒杀、音讯削峰填谷,集群流量管制、实时熔断上游不可用利用等场景熟能生巧
  • 齐备的实时监控: Sentinel 提供了实时的监控性能。通过控制台能够看到接入利用的单台机器的数据,甚至 500 台以下规模的集群的汇总状况
  • 宽泛的开源生态: Sentinel 提供开箱即用的与其余开源框架整合模块,只须要引入相干的依赖进行简略的配置即可疾速接入
  • 欠缺的 SPI 扩大点: Sentinel 提供简略易用、欠缺的 SPI 扩大接口。能够通过扩大接口来疾速定制逻辑。例如定制规定治理,适配动静数据源等

3)组成部分

  • 外围库(Java 客户端):不依赖任何框架 / 库,可能运行于所有的 Java 运行环境,同时对 Dubbo 和 SpringCloud 有很好的反对
  • 控制台(Dashboard):基于 SpringBoot 开发,打包后能够间接运行,不须要额定的 Tomcat 等利用容器

五、上手 Sentinel

既然 Sentinel 有两个组成部分,咱们别离介绍

1)外围库应用

最要害的一步便是引入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

而后编写一个测试控制器

@RestController
@RequestMapping("order")
public class OrderController {private final static Logger LOGGER = LoggerFactory.getLogger(OrderController.class);

    @GetMapping("/create/{id:.+}")
    public String createOrder(@PathVariable String id) {LOGGER.info("筹备下单 ID 为 [{}] 的商品", id);
        LOGGER.info("胜利下单了 ID 为 [{}] 的商品", id);
        return "success";
    }

    @GetMapping("/{id:.+}")
    public String detail(@PathVariable String id) {return StringUtils.join("获取到了 ID 为", id, "的商品");
    }
}

2)控制台应用

Sentinel 具备欠缺的控制台,其实就抓住了国人开发的命点。很多人看到有控制台的应用,毫不犹豫的抉择了它!

  • 首先咱们须要下载控制台的 Jar 包启动运行,下载地址
  • 下载完结进入到下载目录中通过以下命令启动,而后拜访 localhost:8080,即可看到页面
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar

  • 登录控制台(sentinel/sentinel)

到这里咱们就胜利进入 Sentinel的控制台页面了,是不是上手非常简略。但这里控制台还是空荡荡的,那是因为咱们我的项目还没进行控制台的相干配置。咱们回到 store-order 订单服务中,在 application.yaml 中进行配置:

sertinel.transport.port为随便端口号,用来跟控制台交换的端口;sentinel.transport.dashboard 为控制台的拜访地址

配置实现后,咱们便能够启动 store-order 服务,此时再看控制台能够发现曾经有了 store-order 这个服务了

可能有些小伙伴会感觉奇怪,下面说到用来跟控制台交换的端口是干嘛用的?有问题,便有提高!这里咱们能够顺带理解一下控制台的应用原理

当 Sentinel 利用启动后,咱们须要将咱们的微服务程序注册到管制台上,也就是在配置文件中指定控制台的地址,这个是必定的。然而所谓用来跟控制台交换的端口,也就是咱们每个服务都会通过这个端口跟控制台传递数据,控制台也能够通过此端口调用微服务中的监控程序来获取微服务的各种信息。因而这个端口必不可少,而且每个服务都须要具备独立的端口号

3)基本概念

  • 资源

所谓的资源就是 Sentinel 要爱护的货色。资源是 Sentinel 的要害概念,它能够使 Java 应用程序中的任何内容,能够是一个服务,也能够是一个办法,甚至是一段代码。

  • 规定

所谓的规定就是用来定义如何进行爱护资源的,它是作用于资源之上的,定义以什么样的形式爱护资源,次要包含了流量管制规定,熔断降级规定以及零碎爱护规定


咱们来看个简略的例子,咱们设置 order/{id}这个 API 的 QPS 为 1

当咱们一直刷新页面就会发现,曾经进行了流控

在这外面 order/{id}指的就是 资源 ,咱们设置的 QPS 阈值就是 规定

4)重要性能

学会用 Sentinel 之前,咱们须要分明 Sentinel 能为咱们干点什么

(1)流量管制

流量管制在网络传输中是一个罕用的概念,它用于调整网络包的数据。任意工夫到来的申请往往是随机不可控的,而零碎的解决能力是无限的。咱们须要依据零碎的解决能力对流量进行管制,Sentinel 作为一个调配器,能够依据须要把随机的申请调整成适合的形态。

(2)熔断降级

当检测到调用链路中某个资源呈现不稳固的体现,例如申请响应工夫长或者异样比例升高的时候,则对这个资源的调用进行限度,让申请疾速失败,防止影响到其余资源而导致级联故障

Sentinel 采纳了两种伎俩进行解决

  1. 通过并发线程数进行限度

Sentinel 通过限度资源并发线程的数量,来缩小不稳固资源对其余资源的影响。当某个资源呈现不稳固的状况时,例如响应工夫变长,对资源的间接影响就是会造成线程数的逐渐沉积。当 线程数在特定资源上沉积到肯定的数量之后,对该资源的新申请就会回绝。沉积的线程实现工作后才会开始持续承受申请

  1. 通过响应工夫对资源进行降级

除了对并发线程数进行管制之外,Sentinel 还能够通过响应工夫来疾速降级不稳固的资源。当依赖的资源呈现响应工夫过长后,所有对该资源的拜访都会被间接回绝,直到过了指定的工夫窗口之后才会从新复原

这里提一嘴和 Hystrix 的区别

两者的准则实际上都是统一的。都是当一个资源呈现问题时,让其疾速失败,不会波及到其余资源服务。然而在限度的实现上是不一样的

  • Hystrix 采纳的是线程池隔离形式,长处是做到了资源之间的隔离,毛病是减少了线程上下文切换的老本
  • Sentinel 采纳的是通过并发线程的数量和响应工夫来对资源做限度的

集体认为 Sentinel 解决限度的形式更好一些

(3)零碎负载爱护

Sentinel 同时提供零碎维度的自适应爱护能力。当零碎负载较高的时候,如果还继续让申请进入可能会导致系统解体,无奈响应。在集群环境下,会把本应这台机器承载的流量转发到其余机器下来。如果这个时候其余的机器也处在一个解体的边缘状态,Sentinel 提供了对应的爱护机制,让零碎的入口流量和负载达到一个均衡,保证系统在能力方位之内解决最多的申请。

5)流控规定

流控规定,在咱们下面阐明 Sentinel 的基本概念时简略演示了一下。流量管制就是用来监控利用流量的 QPS(每秒查问率)或并发线程数等指标,当达到指定的阈值时对流量进行管制,以防止被刹时的流量顶峰冲垮,从而保障利用的高可用性。

简略配置

簇点链路 —> 抉择对应资源 —> 增加流控

  • 资源名:惟一名称,默认就是申请门路,反对自定义
  • 针对起源: 指定对哪个微服务进行限流,默认为 default(不辨别起源,全副限度)
  • 阈值类型 / 单机阈值

    1. QPS (每秒申请数):当调用该接口的 QPS 达到阈值的时候进行限流
    2. 线程数:当调用该接口的线程数达到阈值的时候进行限流
  • 是否集群: 这里临时不演示集群

高级配置

咱们点开 高级选项 能够看到多出了两个额定性能

其中 流控模式 分为 三种

  • 间接(默认):接口达到限流条件时,开启限流
  • 关联:当关联的资源达到限流条件是,开启限流(适宜做利用退让)
  • 链路: 当从某个接口过去的资源达到限流条件时,开启限流

1、关联流控

间接流控 的形式咱们在下面曾经演示过了,咱们这里间接说 关联流控 如何应用

应用形式也很简略,只有增加相关联的资源即可。只有关联资源 /order/create/{id}的 QPS 每秒超过 1。那么 /order/{id} 就会触发流控。这就是 你激动,我买单

设置完后,咱们须要请咱们的老帮手 Jmeter 帮忙测试一下:

这个时候 /order/create/{id} 的 QPS 曾经远远超过 1 了,而后咱们再试着拜访 /order/{id},发现曾经被限流了!

2、链路流控

链路流控模式指的是:当从某个接口过去的资源达到限流条件的时候,开启限流。它的性能有点相似于针对起源配置项,区别在于:针对起源是针对下级微服务,而链路流控是针对下级接口,也就是说它的粒度更细

该模式应用麻烦一些,咱们须要革新下代码:

OrderService

OrderController

application.yaml

而后自定义 Sentinel 上下文过滤类 FilterContextConfig

接下来咱们在 Sentinel 控制台流控中增加配置:

而后咱们看测试后果,发现以 /order/_datail02 为入口拜访,会进行流控,而 /order/_datail01 拜访便不会进行流控

因而咱们分明了 链路模式 的入口资源是针对办法接口的

6)降级规定

降级规定指的就是当满足什么条件的时候,对服务进行降级。Sentinel 提供了三个掂量条件:

  • 慢调用比例

    当资源的均匀相应工夫超过阈值(单位 ms)之后,资源进入准降级的状态。如果接下来 1s 内继续进入 5 个申请,它们的 RT 都继续超过这个阈值,那么在接下来的工夫窗口(单位 s)之内,就会对这个办法进行降级。

  • 异样比例

当资源的 每秒异样总数 / 占通过量 的比率超过阈值之后,资源就会进入升高状态,即在接下的工夫窗口(单位 s)之内,对这个办法的调用都会主动的返回。异样比率的赋值范畴为 [0.0, 1.0]

  • 异样数

当资源近 1 分钟的异样数目超过阈值之后就会间接进行降级。然而这里须要留神的是,因为统计工夫窗口是分钟级别的,若工夫窗口小于 60s,则完结熔断状态后仍可能再进入熔断状态

7)热点规定

热点参数流控规定是一种更加细粒度的流控规定,它容许将规定具体到参数上。这里咱们能够在代码外面具体看下怎么应用

@SentinelResource("order")  // 不增加该注解标识, 热点规定不失效
@GetMapping("/_datail03")
public String detail03(String arg1, String arg2) {return StringUtils.join(arg1, arg2);
}

该 API 接管两个参数 arg1arg2,这个时候咱们对这个资源增加参数流控

弄完下面配置后,咱们就能够在浏览器进行测试了

当参数为第二个的时候,无论一秒刷新几次都不会触发流控

当参数为第一个的时候,只有 QPS 超过了 1,就会触发流控

这个配置也有高级选项,能够更细颗粒的对参数进行限度,这里就不再演示了。

8)零碎规定

零碎爱护规定是从利用级别的入口流量进行管制,从单台机器总体的 Load、RT、线程数、入口 QPS、CPU 使用率 五个维度监控利用数据,让零碎尽可能跑在最大吞吐量的同时保证系统整体的稳定性

  • Load: 仅对 Linux/Unix 无效。当零碎的 load 超过阈值时,且零碎以后的并发线程数超过零碎容量时才会触发零碎爱护。零碎容量是由零碎的 maxQPS * minRT 计算而出,设定的参考值能够参考 CPU 核数 * 2.5
  • RT: 当单台机器上所有入口流量的均匀 RT 达到阈值就会触发零碎爱护,单位是毫秒
  • 线程数: 当单台机器上所有入口流量的并发线程数达到阈值是就会触发爱护
  • 入口 QPS: 当单台机器上所有入口流量的 QPS 达到阈值就会触发零碎爱护
  • CPU 使用率: 当单台机器上所有入口流量的 CPU 使用率达到阈值就会触发零碎爱护

9)受权规定

在某些场景下,咱们须要依据调用起源来判断该次申请是否容许放行,这个时候咱们能够应用 Sentinel 的起源访问控制的性能。起源访问控制依据资源的申请起源判断资源是否可能通过

  • 白名单: 只有申请起源位于白名单内能力通过
  • 黑名单: 申请起源位于黑名单时不予通过,其余的则放行通过

那么问题来了,流控利用 是啥玩意?要用这个流控利用,咱们还须要借助 Sentinel 中的 RequestOriginParser 接口来解决起源。只有 Sentinel 爱护的接口资源被拜访,Sentinel 就会调用 RequestOriginParser 的实现类去解析拜访源

CustomRequestOriginParser

public class CustomRequestOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {return httpServletRequest.getParameter("api");
    }
}

而后咱们增加受权规定

该规定的作用是,只有当申请 URL 中带有参数 api=detail03 能力拜访胜利,否则失败。以下便是测试后果

六、扩大 Sentinel

1)@SentinelResource

这个注解咱们下面曾经用过,不晓得小伙伴们有没有留神到,下面避开没讲就是为了在这具体的介绍下!

该注解的作用就是用来定义资源点。当咱们定义了资源点之后,就能够通过 Sentinel 控制台来设置限流和降级策略来对资源点进行爱护。同时还能够通过该注解来指定出现异常时候的解决策略。

咱们点进注解能够看到该注解中存在许多属性

属性 作用
value 资源点名称
blockHandle 解决 BlockException 的函数名称,函数要求:
1. 必须是 public
2. 返回类型参数与原办法要统一
3. 默认需和原办法在同一个类中。如果心愿应用其余类的函数,能够配置 blockHandlerClass,并制订 blockHandlerClass 外面的办法
blackHandlerClass 寄存 blockHandler 的类,对应的处理函数必须用 static 润饰
fallback 用于在抛出异样时候提供 fallback 解决逻辑。fallback 函数能够针对所有类型的异样(除了 exceptionsToIgnore 中排除的异样),函数要求:
1. 返回类型与原办法统一
2. 参数类型需和原办法匹配
3. 默认需和原办法在同一个类中。若心愿应用其余类的函数,可配置 fallbackClass,并指定对应的办法
fallbackClass 寄存 fallback 的类,对应的处理函数必须用 static 润饰
defaultFallback 用于通用的 fallback 逻辑。默认 fallback 函数能够针对所有类型的异样进行解决。若同时配置了 fallback 和 defaultFallback,以 fallback 为准。函数要求:<br/>1. 返回类型与原办法统一 <br/>2. 办法参数列表为空,或者有一个 Throwable 类型的参数。<br/>3. 默认须要和原办法在同一个类中。若心愿应用其余类的函数,可配置 fallbackClass,并指定 fallbackClass 外面的办法。
exceptionsToIgnore 指定排除掉哪些异样。排除的异样不会计入异样统计,也不会进入 fallback 逻辑,而是原样抛出。
exceptionsToTrace 须要 trace 的异样

咱们这里简略应用演示一下

  • 将限流和降级办法定义在原办法同一个类中

  • 限流和降级办法定义不在原办法同一个类中

而后咱们做个简略的流控设置:

拜访后果:

这种提醒的形式显然更加敌对!

2)Sentinel 规定长久化

曾经上手尝试的同学可能会发现一个问题,当咱们的我的项目重启,或者 Sentinel 控制台重启都会导致配置被清空了!这是因为这些规定默认是寄存在内存中,这可是很大的问题!因而 规定长久化 是一个必不可少的工作!当然在 Sentinel 也曾经很好的反对了这项性能,解决逻辑如下:

瞎话说配置类代码有点长,这里间接贴代码了,有须要的小伙伴能够拷过来间接用!

public class FilePersistence implements InitFunc {

    @Override
    public void init() throws Exception {String ruleDir = new File("").getCanonicalPath() +"/sentinel-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);
        // 流控规定 sentinel
        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 final Converter<String, List<FlowRule>> flowRuleListParser = source ->
            JSON.parseObject(
                    source,
                    new TypeReference<List<FlowRule>>() {}
            );

    private final Converter<String, List<DegradeRule>> degradeRuleListParser = source
            -> JSON.parseObject(
            source,
            new TypeReference<List<DegradeRule>>() {}
    );

    private final Converter<String, List<SystemRule>> systemRuleListParser = source ->
            JSON.parseObject(
                    source,
                    new TypeReference<List<SystemRule>>() {}
            );
    private final Converter<String, List<AuthorityRule>> authorityRuleListParser =
            source -> JSON.parseObject(
                    source,
                    new TypeReference<List<AuthorityRule>>() {}
            );
    private final 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 在文件中增加配置类的全门路

这样子咱们启动我的项目的时候就会生成 Sentinel 的配置文件了

当咱们在控制台中增加一条流控规定后,对应的 json 文件就会有对应的配置

到这里咱们就实现了 Sentinel 的长久化性能,到这里咱们也实现了对 SpringCloud 中 Sentinel 的介绍!

前面会持续整顿对于 SpringCloud 组件的文章,敬请关注!

不要空谈,不要贪懒,和小菜一起做个 吹着牛 X 做架构 的程序猿吧~ 点个关注做个伴,让小菜不再孤独。咱们下文见!

明天的你多致力一点,今天的你就能少说一句求人的话!

我是小菜,一个和你一起变强的男人。 💋

微信公众号已开启,小菜良记,没关注的同学们记得关注哦!

正文完
 0