当前位置: 首页 > news >正文

SpringCloudAlibaba之Sentinel介绍

文章目录

  • 1 Sentinel
    • 1.1 Sentinel简介
    • 1.2 核心概念
      • 1.2.1 资源
      • 1.2.2 规则
    • 1.3 入门Demo
      • 1.3.1 引入依赖
      • 1.3.2 集成Spring
      • 1.3.3 Spring中资源规则
    • 1.4 Sentinel控制台
    • 1.5 核心原理
      • 1.5.1 NodeSelectorSlot
      • 1.5.2 ClusterBuilderSlot
      • 1.5.3 LogSlot
      • 1.5.4 StatisticSlot
      • 1.5.5 AuthoritySlot
      • 1.5.6 SystemSlot
      • 1.5.7 FlowSlot
      • 1.5.8 DegradeSlot
    • 1.6 注解方式定义资源示例
      • 1.6.1 Maven 依赖
      • 1.6.2 AspectJ 的配置类
      • 1.6.3 controller 层
    • 1.7 持久化配置
      • 1.7.1 pull模式
        • 1.7.1.1 pom.xml
        • 1.7.1.2 配置类
        • 1.7.1.3 添加到服务中
      • 1.7.2 push模式
        • 1.7.2.1 pom.xml
        • 1.7.2.2 yml配置

1 Sentinel

1.1 Sentinel简介

Sentinel是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。
主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

上面两句话来自Sentinel官网的自我介绍,从这短短的两句话就可以看出Sentinel的定位和拥有的强大功能。

1.2 核心概念

要想理解一个新的技术,那么首先你得理解它的一些核心概念

1.2.1 资源

资源是Sentinel中一个非常重要的概念,资源就是Sentinel所保护的对象。

资源可以是一段代码,又或者是一个接口,Sentinel中并没有什么强制规定,但是实际项目中一般以一个接口为一个资源,比如说一个http接口,又或者是rpc接口,它们就是资源,可以被保护。

资源是通过SentinelAPI定义的,每个资源都有一个对应的名称,比如对于一个http接口资源来说,Sentinel默认的资源名称就是请求路径。

1.2.2 规则

规则也是一个重要的概念,规则其实比较好理解,比如说要对一个资源进行限流,那么限流的条件就是规则,后面在限流的时候会基于这个规则来判定是否需要限流。

Sentinel的规则分为流量控制规则、熔断降级规则以及系统保护规则,不同的规则实现的效果不一样。

1.3 入门Demo

1.3.1 引入依赖

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.6</version>
</dependency>

测试代码

public class SentinelSimpleDemo {public static void main(String[] args) {//加载流控规则initFlowRules();for (int i = 0; i < 5; i++) {Entry entry = null;try {entry = SphU.entry("sayHello");//被保护的逻辑System.out.println("访问sayHello资源");} catch (BlockException ex) {System.out.println("被流量控制了,可以进行降级处理");} finally {if (entry != null) {entry.exit();}}}}private static void initFlowRules() {List<FlowRule> rules = new ArrayList<>();//创建一个流控规则FlowRule rule = new FlowRule();//对sayHello这个资源限流rule.setResource("sayHello");//基于qps限流rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//qps最大为2,超过2就要被限流rule.setCount(2);rules.add(rule);//设置规则FlowRuleManager.loadRules(rules);}}

解释一下上面这段代码的意思

  • initFlowRules:方法就是加载一个限流的规则,这个规则作用于sayHello这个资源,基于qps限流,当qps超过2之后就会触发限流。
  • SphU.entry("sayHello"):这行代码是Sentinel最最核心的源码,这行代码表面看似风平浪静,实则暗流涌动。这行代码表明接下来需要访问某个资源(参数就是资源名称),会去检查需要被访问的资源是否达到设置的流控、熔断等规则。对于demo来说,就是检查sayHello这个资源是否达到了设置的流量控制规则。
  • catch BlockException:也很重要,当抛出BlockException这个异常,说明触发了一些设置的保护规则,比如限流了,这里面就可以进行降级操作。
  • System.out.println("访问sayHello资源"):这行代码表面是一个打印语句,实则就是前面一直在说的需要被保护的资源。

所以上面这段代码的整体意思就是对 sayHello这个需要访问的资源设置了一个流控规则,规则的内容是当qps到达2的时候触发限流,之后循环5次访问sayHello这个资源,在访问之前通过SphU.entry("sayHello")这行代码进行限流规则的检查,如果达到了限流的规则的条件,会抛出BlockException

1.3.2 集成Spring

在实际的项目使用中一般不会直接写上面的那段demo代码,而是集成到Spring环境底下。

引入依赖

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.6.11</version>
</parent>
<dependencies>
<!-- 与springcloud集成使用 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
</dependencies><!-- 需要spring-boot、spirng-cloud、spirng-cloud-alibaba -->
<dependencyManagement><dependencies><!--springcloud父依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2021.0.4.0</version><type>pom</type><scope>import</scope></dependency><!--springcloudalibaba父依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2021.0.4.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

之后提供一个/sayHello接口

@RestController
public class SentinelDemoController {@GetMapping("/sayHello")public String sayHello() throws InterruptedException {return "hello";}}

配置文件

server:port: 9527spring:application:name: SentinelDemo

到这demo就搭建完成了。

1.3.3 Spring中资源规则

那么那前面提到的资源和对应的规则去哪了?
前面在说资源概念的时候,提到 Sentinel 中默认一个http接口就是一个资源,并且资源的名称就是接口的请求路径。而真正的原因是Sentinel实现了SpringMVC中的HandlerInterceptor接口,在调用Controller接口之前,会将一个调用接口设置为一个资源,代码如下
在这里插入图片描述

getResourceName方法就是获取资源名,其实就是接口的请求路径,比如前面提供的接口路径是/sayHello,那么资源名就是/sayHello
再后面的代码就是调用上面demo中提到表面风平浪静,实则暗流涌动的SphU.entry(..)方法,检查被调用的资源是否达到了设置的规则。

好了,既然资源默认是接口,已经有了,那么规则呢?
规则当然可以按照第一个demo的方式来做,比如在Controller接口中加载,代码如下。

@RestController
public class SentinelDemoController {static {List<FlowRule> rules = new ArrayList<>();//创建一个流控规则FlowRule rule = new FlowRule();//对/sayHello这个资源限流rule.setResource("/sayHello");//基于qps限流rule.setGrade(RuleConstant.FLOW_GRADE_QPS);//qps最大为2,超过2就要被限流rule.setCount(2);rules.add(rule);//设置规则FlowRuleManager.loadRules(rules);}@GetMapping("/sayHello")public String sayHello() throws InterruptedException {return "hello";}}

此时启动项目,在浏览器输入以下链接

http://127.0.0.1:9527/sayHello

疯狂快速使劲地多点几次,就出现下面这种情况
在这里插入图片描述

可以看出规则生效了,接口被Sentinel限流了,至于为什么出现这个提示,是因为Sentinel有默认的处理BlockException的机制,就在前面提到的进入资源的后面。
在这里插入图片描述

当然,也可以自定义处理的逻辑,实现BlockExceptionHandler接口就可以了。

1.4 Sentinel控制台

虽然上面这种硬编码规则的方式可以使用,但是在实际的项目中,肯定希望能够基于系统当期那运行的状态来动态调整规则,所以Sentinel提供了一个叫Dashboard应用的控制台,可以通过控制台来动态修改规则。
下载地址:https://github.com/alibaba/Sentinel/releases,下载第一个即可
在这里插入图片描述

图片

控制台其实就是一个jar包,可以从Sentinel的github仓库上下载。
之后通过java -jar命令启动就可以了,端口默认8080,浏览器访问 http://ip:8080/#/login就可以登录控制台了,用户名和密码默认都是 sentinel
java -Dserver.port=8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar

那么问题来了:默认的用户名和密码在生产环境上肯定不能用,如何修改呢?
Sentinel 1.6.0sentinel 已经支持自定义用户名和密码了,只需要在执行jar命令时指定即可,命令如下:

启动命令:

java -Dserver.port=8080-Dcsp.sentinel.dashboard.server=localhost:8080-Dproject.name=sentinel-dashboard-Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=123 -jar sentinel-dashboard-1.7.1.jar

用户可以通过如下参数进行配置:

  • -Dserver.port:指定启动的端口,默认8080
  • -Dproject.name:指定本服务的名称
  • -Dcsp.sentinel.dashboard.server:指定sentinel控制台的地址,用于将自己注册进入实现监控自己
  • -Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;
  • -Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;如果省略这两个参数,默认用户和密码均为 sentinel;
  • -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;

此时服务要接入控制台,只需要在配置文件上加上控制台的ip和端口即可

spring:cloud:sentinel:# 取消控制台懒加载eager: truetransport:# 指定控制台的ip和端口dashboard: localhost:8080

项目刚启动的时候控制台默认是没有数据的,需要访问一下接口,之后就有了。

图片

之后就可以看到/sayHello这个资源,后面就可以通过页面设置规则。

1.5 核心原理

讲完demo,接下来就来讲一讲 Sentinel 的核心原理,也就是前面提到暗流涌动的SphU.entry(..)这行代码背后的逻辑。
Sentinel会为每个资源创建一个处理链条,就是一个责任链,第一次访问这个资源的时候创建,之后就一直复用,所以这个处理链条每个资源有且只有一个。
SphU.entry(..)这行代码背后就会调用责任链来完成对资源的检查逻辑。

这个责任链条中每个处理节点被称为 ProcessorSlot,中文意思就是处理器槽
在这里插入图片描述

这个ProcessorSlot有很多实现,但是Sentinel的核心就下面这8个:

  • NodeSelectorSlot
  • ClusterBuilderSlot
  • LogSlot
  • StatisticSlot
  • AuthoritySlot
  • SystemSlot
  • FlowSlot
  • DegradeSlot

这些实现会通过SPI机制加载,然后按照一定的顺序组成一个责任链。

默认情况下,节点是按照如下的顺序进行排序的
在这里插入图片描述
虽然默认就8个,但是如果你想扩展,只要实现ProcessorSlot,按照SPI的规定配置一下就行。

下面就来按照上面节点的处理顺序来好好扒一扒这8个ProcessorSlot

1.5.1 NodeSelectorSlot

这个节点的作用是来设置当前资源对应的入口的统计Node。

首先什么是统计Node?
比如就拿上面的例子来说,当 /sayHello 这个资源的qps超过2的时候,要触发限流。
但是有个疑问,Sentinel是怎么知道/sayHello这个资源的qps是否达到2呢?

当然是需要进行数据统计的,只有通过统计,才知道qps是否达到2,这个进行数据统计的类在Sentinel中叫做Node。

public interface Node extends OccupySupport, DebugSupport{long totalRequest();long totalPass();long totalSuccess();long blockRequest();long totalException();double passQps();
}

通过Node这个统计的类就知道有多少请求,成功多少个,失败多少个,qps是多少之类的。底层其实是使用到了滑动窗口算法。

那么什么叫对应的入口?
Sentinel中,支持同一个资源有不同的访问入口。
举个例子,这个例子后面会反复提到。
假设把杭州看做是服务,西湖看做是一个资源,到达西湖有两种方式,地铁和公交。

图片

所以要想访问西湖这个资源,就可以通过公交和地铁两种方式,而公交和地铁就对应前面说的入口的意思。
只不过一般一个资源就一个入口,比如一个http接口一般只能通过http访问,但是Sentinel支持多入口,你可以不用,但是Sentinel有。

所以NodeSelectorSlot的作用就是选择资源在当前调用入口的统计Node,这样就实现了统计同一个资源在不同入口访问数据,用上面的例子解释,就可以实现分别统计通过公交和地铁访问西湖的人数。

资源的入口可以在进入资源之前通过ContextUtil.enter("入口名", origin)来指定,如果不指定,那么入口名称默认就是sentinel_default_context

SpringMVC环境底下,所有的http接口资源,默认的入口都是sentinel_spring_web_context

图片

入口名称也可以通过控制台看到

图片

1.5.2 ClusterBuilderSlot

ClusterBuilderSlot 的作用跟 NodeSelectorSlot 其实是差不多的,也是用来选择统计Node,但是选择的Node的统计维护跟 NodeSelectorSlot 不一样。

ClusterBuilderSlot会选择两个统计Node

  • 第一个统计Node是资源的所有入口的统计数据之和,就是资源访问的总数据
  • 第二个统计Node就是统计资源调用者对资源访问数据

资源调用者很好理解,比如一个http接口资源肯定会被调用,那么调用这个接口的服务或者应用其实就是资源的调用者,但是一般资源的调用者就是指某个服务,后面调用者我可能会以服务来代替。

一个接口可以被很多服务调用,所以一个资源可以很多调用者,而不同调用者都会有单独的一个统计 Node,用来分别统计不同调用者对资源的访问数据。

举个例子,现在访问西湖这个资源的大兄弟来自上海,那么就会为上海创建一个统计Node,用来统计所有来自上海的人数,如果是北京,那么就会为北京创建一个统计Node

那么如何知道访问资源来自哪个服务(调用者)呢?
也是通过ContextUtil.enter("入口名", origin)来指定,这个方法的第二个参数origin就是代表服务名的意思,默认是空。
所以ContextUtil.enter(..)可以同时指定资源的入口和调用者,一个资源一定有入口,因为不指定入口默认就是sentinel_default_context,但是调用者不指定就会没有。
对于一个http请求来说,Sentinel默认服务名需要放到S-user这个请求头中,所以如果你想知道接口的调用服务,需要在调用方发送请求的时候将服务名设置到S-user请求头中。
当资源所在的服务接收到请求时,Sentinel就会从S-user请求头获取到服务名,之后再通过ContextUtil.enter("入口名", "调用者名")来设置当前资源的调用者

图片

这里原以为 Sentinel 会适配比如OpenFeign之类的框架,会自动将服务名携带到请求头中,但是翻了一下源码,发现并没有去适配,不知道是出于什么情况的考虑。

所以这一节加上上一节,知道了一个资源其实有三种维度的统计Node

  • 分别统计不同入口的访问数据
  • 统计所有入口访问数据之和
  • 分别统计来自某个服务的访问数据

为了方便区分,给这三个统计Node取个响亮的名字
不同入口的访问数据就叫他DefaultNode,统计所有入口访问数据之和就叫他ClusterNode,来自某个服务的访问数据就叫他OriginNode

那么他们的关系就可以用下面这个图来表示

图片

1.5.3 LogSlot

这个Slot没什么好说的,通过名字可以看出来,其实就是用来打印日志的。
在这里插入图片描述
当发生异常,就会打印日志。

1.5.4 StatisticSlot

这个 Slot 就比较重要了,就是用来统计数据的。
前面说的 NodeSelectorSlotClusterBuilderSlot,他们的作用就是根据资源当前的入口和调用来源来选择对应的统计Node
StatisticSlot就是对这些统计Node进行实际的统计,比如加一下资源的访问线程数,资源的请求数量等等。
图片

前几个Slot其实都是准备、统计的作用,并没有涉及限流降级之类的,他们是为限流降级提供数据支持的。

1.5.5 AuthoritySlot

Authority是授权的意思,这个Slot的作用是对资源调用者进行授权,就是黑白名单控制。
可以通过控制台来添加授权规则。
在这里插入图片描述

AuthoritySlot中会去获取资源的调用者,之后会跟授权规则中的资源应用这个选项进行匹配,之后就会出现有以下2种情况:

  • 授权类型是黑名单,匹配上了,说明在黑名单内,那么这个服务就不能访问这个资源,没匹配上就可以访问
  • 授权类型是白名单。匹配上了,说明在白名单内,那么这个服务就可以访问这个资源,没匹配上就不可以访问

1.5.6 SystemSlot

这个的作用是根据整个系统运行的统计数据来限流的,防止当前系统负载过高。
它支持入口qps、线程数、响应时间、cpu使用率、负载5个限流的维度。

图片

对于系统的入口qps、线程数、平均响应时间这些指标,也会有一个统计Node专门去统计,所以这个统计Node的作用就好比会去统计所有访问西湖的人数,统计也在StatisticSlot代码中,前面说的时候把代码隐藏了

图片

至于cpu使用率、负载指标,Sentinel会启动一个定时任务,每隔1s会去读取一次当前系统的cpu和负载。

1.5.7 FlowSlot

这个Slot会根据预设的规则,结合前面的统计出来的实时信息进行流量控制。
在说FlowSlot之前,先来用之前画的那张图回顾一下一个资源的三种统计维度

图片

这里默默地注视10s。。

限流规则配置项比较多

图片

这里我们来好好扒一扒这些配置项的意思。

  • 针对来源,来源就是前面说的调用方,这个配置表明,这个规则适用于哪个调用方,默认是default,就是指规则适用于所有调用方,如果指定了调用方,那么这个规则仅仅对指定的调用方生效。
    举个例子来说,比如说现在想限制来自上海的访问的人数,那么针对来源可以填上海,之后当访问的大兄弟来自上海的时候,Sentinel就会根据上海对应的OriginNode数据来判断是否达到限流的条件。
  • 阈值类型,就是限流条件,当资源的qps或者访问的线程数到达设置的单机阈值,就会触发限流。
  • 是否集群,这个作用是用来对集群控制的,因为一个服务可能在很多台机器上,而这个的作用就是将整个集群看成一个整体来限流,这里就不做深入讨论。
  • 流控模式,这个流控模式的选项仅仅对阈值类型为qps有效,当阈值类型线程数时无效。这个配置就比较有意思了,分为直接、关联、链路三种模式。
    • 直接模式的意思就是当资源的ClusterNode统计数据统计达到了阈值,就会触发限流。
      比如,当通过地铁和公交访问西湖人数之和达到单机阈值之后就会触发限流。
    • 关联模式下需要填写关联的资源名称
      关联的意思就是当关联资源的ClusterNode统计的qps达到了设置的阈值时,就会触发当前资源的限流操作。
      比如,假设现在西湖这个资源关联了雷峰塔这个资源,那么当访问雷峰塔的人数达到了指定的阈值之后,此时就触发西湖这个资源的限流,就是雷峰塔流量高了但是限流的是西湖。

图片
链路模式也一样,它需要关联一个入口资源

图片

关联入口的意思就是指,当访问资源的实际入口跟关联入口是一样的时候,就会根据这个入口对应的DefaultNode的统计数据来判断是否需要限流。
也就是可以单独限制通过公交和地铁的访问的人数的意思。

到这,其实前面说到的一个资源的三种统计维度的数据都用到了,现在应该明白了为什么需要这么多维度的数据,就是为不同维度限流准备的。

最后一个配置项,流控效果,这个就是如果是通过qps来限流,并且达到了限流的条件之后会做什么,如果是线程数,就直接抛出BlockException异常
也有三种方式,快速失败、Warm Up、排队等待

  • 快速失败:意思就是指一旦触发限流了,那么直接抛出BlockException异常
  • Warm Up:的作用就是为了防止系统流量突然增加时出现瞬间把系统压垮的情况。通过冷启动,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限。
  • 排队等待,很好理解,意思当出现限流了,不是抛异常,而是去排队等待一定时间,其实就是让请求均匀速度通过,内部使用的是传说中的漏桶算法。

1.5.8 DegradeSlot

这是整个责任链中最后一个slot,这个slot的作用是用来熔断降级的。
Sentinel支持三种熔断策略:慢调用比例、异常比例 、异常数,通过规则配置也可以看出来。

图片

熔断器的工作流程大致如下

图片

Sentinel会为每个设置的规则都创建一个熔断器,熔断器有三种状态,OPEN(打开)HALF_OPEN(半开)CLOSED(关闭)

当处于CLOSED状态时,可以访问资源,访问之后会进行慢调用比例、异常比例、异常数的统计,一旦达到了设置的阈值,就会将熔断器的状态设置为OPEN
当处于OPEN状态时,会去判断是否达到了熔断时间,如果没到,拒绝访问,如果到了,那么就将状态改成HALF_OPEN,然后访问资源,访问之后会对访问结果进行判断,符合规则设置的要求,直接将熔断器设置为CLOSED,关闭熔断器,不符合则还是改为OPEN状态
当处于HALF_OPEN状态时,直接拒绝访问资源

一般来说,熔断降级其实是对于服务的调用方来说的。

在项目中会经常调用其它服务或者是第三方接口,而对于这些接口,一旦它们出现不稳定,就有可能导致自身服务长时间等待,从而出现响应延迟等等问题。

此时服务调用方就可基于熔断降级方式解决。
一旦第三方接口响应时间过长,那么就可以使用慢调用比例规则,当出现大量长时间响应的情况,那么就直接熔断,不去请求。
虽然说熔断降级是针对服务的调用方来说,但是Sentinel本身并没有限制熔断降级一定是调用其它的服务。

1.6 注解方式定义资源示例

Sentinel 支持通过 @SentinelResource 注解来定义资源,并配置 blockHandler 函数来进行限流之后的处理,如果是使用spring-cloud-starter-alibaba-sentinel,则不需要添加依赖可以直接使用注解

1.6.1 Maven 依赖

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-annotation-aspectj</artifactId><version>1.8.0</version>
</dependency>

1.6.2 AspectJ 的配置类

@Configuration
public class SentinelAspectConfiguration {@Beanpublic SentinelResourceAspect sentinelResourceAspect(){return new SentinelResourceAspect();}
}

1.6.3 controller 层

@Controller
public class Test2Controller {// value:资源名称 blockHandler:设置限流或降级处理的类@SentinelResource(value = "/ann", blockHandler = "exceptionHandler")@ResponseBody@RequestMapping(path = "/ann", method = RequestMethod.GET)public String ann() {// 使用限流规则return "Hello Sentinel";}public String exceptionHandler(@NotNull BlockException e) {e.printStackTrace();return "系统繁忙,请稍后再试";}
}

在这里插入图片描述

1.7 持久化配置

现在 sentinel 控制台存在这么一个问题,当重新登录控制台或者关闭服务,控制台的流控规则就消失了。

sentinel持久化有三种模式

推送模式说明优点缺点
原始模式API将规则推送至客户端并直接更新到内存中,扩展写数据源简单,无任何依赖不保证一致性;规则保存在内存中,重启即消失,不建议用于生产环境
Pull模式扩展写数据源,客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是RDBMS、文件等简单,无任何依赖;规则持久化不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题
Push模式扩展读数据源,规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用Nacos,zookeeper 等配置中心。这种方式有更好的实时性和一致保证。生产环境下一般采用push模式的数据源规则持久化;一致性;快速引入第三方依赖

1.7.1 pull模式

此模式需要编写一点配置代码,将规则持久化到本地文件。

1.7.1.1 pom.xml

<!--sentinel持久化pull模式到本地文件-->
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-extension</artifactId>
</dependency>

1.7.1.2 配置类

package com.dbcenter.service.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 FileDataSourceInit implements InitFunc {@Overridepublic void init() throws Exception {
// TIPS: 如果你对这个路径不喜欢,可修改为你喜欢的路径String ruleDir = System.getProperty("user.home") + "/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 hotParamFlowRulePath = ruleDir + "/param-flow-rule.json";this.mkdirIfNotExits(ruleDir);this.createFileIfNotExits(flowRulePath);this.createFileIfNotExits(degradeRulePath);this.createFileIfNotExits(systemRulePath);this.createFileIfNotExits(authorityRulePath);this.createFileIfNotExits(hotParamFlowRulePath);// 流控规则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>> hotParamFlowRuleRDS = new FileRefreshableDataSource<>(hotParamFlowRulePath,hotParamFlowRuleListParser);ParamFlowRuleManager.register2Property(hotParamFlowRuleRDS.getProperty());WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(hotParamFlowRulePath,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>> hotParamFlowRuleListParser = source -> JSON.parseObject(source,new TypeReference<List<ParamFlowRule>>() {});/*** 创建目录** @param filePath*/private void mkdirIfNotExits(String filePath) {File file = new File(filePath);if (!file.exists()) {file.mkdirs();}}/*** 创建文件** @param filePath* @throws IOException*/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.7.1.3 添加到服务中

resource下新增配置文件,名字为 com.alibaba.csp.sentinel.init.InitFunc
在这里插入图片描述
内容为上面配置类的全类名
在这里插入图片描述
重启项目,配置相关限流规则,就可以在对应目录看到相关持久化配置文件了

由于此种方式是客户端定时从规则中心拉取规则,所以,可能会出现sentinel客户端显示不及时的情况。经过测试,当被配置的微服务重启后,基本上需要10分钟才会再控制台上显示。
在这里插入图片描述
但是其实只要服务启动起来,其配置规则还是先生效的,即使控制台不显示配置信息,然后经过10分钟左右后,信息就会同步到控制台。

1.7.2 push模式

我们可以将流控规则持久化进 nacos进行保存。只要刷新微服务的某个rest地址,sentinel控制台的流控规则就能看到,只要nacos里面的配置不删除,针对改微服务的流控规则持续有效

1.7.2.1 pom.xml

<!-- 此种方式是用的 spring-cloud-starter-alibaba-sentinel 依赖--><!-- Nacos配置中心修改的规则可能实时同步至Sentinel控制台-->
<!-- Sentinel Datasource 依赖 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency><!--sentinel持久化到nacos用到-->
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

1.7.2.2 yml配置

yml添加配置

spring:cloud:sentinel:# 取消控制台懒加载eager: truetransport:# 指定控制台的ip和端口dashboard: localhost:8080datasource:flow:nacos:server-addr: localhost:8848namespace: xxxxusername: xxxxpassword: xxxxdataId: application-flow.jsongroupId: DEFAULT_GROUPdata-type: json#热点规则配置rule-type: PARAM_FLOW

nacos中的配置

[
{"resource":"/say/hello",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}]

参数说明:

  • resource:资源名称
  • limitApp:来源应用
  • grade:阈值类型,0:表示线程数,1:表示QPS
  • count:单机阈值
  • strategy:流控模式,0:直接,1:关联,2:链路
  • controlBehavior:流控效果,0:快速失败,1:Warm Up,2排队等待
  • clusterMode:是否集群
  • rule-type:表示规则类型。规则类型用于区分不同类型的规则,以便在Sentinel中正确解析和应用这些规则。根据注释,可以看到以下规则类型选项:
    • PARAM_FLOW:热点参数流控规则
    • FLOW:限流规则
    • DEGRADE:降级规则
    • SYSTEM:系统保护规则

相关文章:

SpringCloudAlibaba之Sentinel介绍

文章目录 1 Sentinel1.1 Sentinel简介1.2 核心概念1.2.1 资源1.2.2 规则 1.3 入门Demo1.3.1 引入依赖1.3.2 集成Spring1.3.3 Spring中资源规则 1.4 Sentinel控制台1.5 核心原理1.5.1 NodeSelectorSlot1.5.2 ClusterBuilderSlot1.5.3 LogSlot1.5.4 StatisticSlot1.5.5 Authority…...

苹果微信聊天记录删除了怎么恢复?果粉原来是这样恢复的

粗心大意删除了微信聊天记录&#xff1f;有时候&#xff0c;一些小伙伴可能只是想要删除一部分聊天记录&#xff0c;但是在进行批量删除时&#xff0c;不小心勾选到了很重要的对话&#xff0c;从而导致记录丢失。 如果这时想找回聊天记录该怎么办&#xff1f;微信聊天记录删除…...

JVM的故事——虚拟机字节码执行引擎

虚拟机字节码执行引擎 文章目录 虚拟机字节码执行引擎一、概述二、运行时栈帧结构三、方法调用 一、概述 执行引擎Java虚拟机的核心组成之一&#xff0c;它是由软件自行实现的&#xff0c;能够执行那些不被硬件直接支持的指令集格式。 对于不同的虚拟机实现&#xff0c;执行引…...

设计模式之适配器与装饰器

目录 适配器模式 简介 角色 使用 优缺点 使用场景 装饰器模式 简介 优缺点 模式结构 使用 使用场景 适配器模式 简介 允许将不兼容的对象包装成一个适配器类&#xff0c;使得其他类可以通过适配器类与原始对象进行交互&#xff0c;从而提高兼容性 角色 目标角色…...

服务器数据恢复- Ext4文件系统分区挂载报错的数据恢复案例

Ext4文件系统相关概念&#xff1a; 块组&#xff1a;Ext4文件系统的空间被划分为若干个块组&#xff0c;每个块组内的结构大致相同。 块组描述符表&#xff1a;每个块组都对应一个块组描述符&#xff0c;这些块组描述符统一放在文件系统的前部&#xff0c;称为块组描述符表。每…...

19-springcloud(上)

一 微服务架构进化论 单体应用阶段 (夫妻摊位) 在互联网发展的初期&#xff0c;用户数量少&#xff0c;一般网站的流量也很少&#xff0c;但硬件成本较高。因此&#xff0c;一般的企业会将所有的功能都集成在一起开发一个单体应用&#xff0c;然后将该单体应用部署到一台服务器…...

前端基础---HTML笔记汇总一

HTML定义 HTML超文本标记语言——HyperText Markup Language。 超文本是什么&#xff1f; 链接标记是什么&#xff1f; 标记也叫标签&#xff0c;带尖括号的文本 标签分类 单标签:只有开始标签&#xff0c;没有结束标签(<br>换行 <hr>水平线 <img> 图像标…...

智汇云舟亮相中国安防工程商集成商大会

智汇云舟亮相中国安防工程商集成商大会&#xff0c;以视频孪生驱动安防行业数字化转型 近日&#xff0c;由中国安全防范产品行业协会指导&#xff0c;永泰传媒主办的中国安防工程商&#xff08;系统集成商&#xff09;大会暨第69届中国安防新产品、新技术成果展示在石家庄圆满…...

使用 Sealos 在离线环境中光速安装 K8s 集群

作者&#xff1a;尹珉。Sealos 开源社区 Ambassador&#xff0c;云原生爱好者。 当容器化交付遇上离线环境 在当今快节奏的软件交付环境中&#xff0c;容器化交付已经成为许多企业选择的首选技术手段。在可以访问公网的环境下&#xff0c;容器化交付不仅能够提高软件开发和交付…...

算法-模拟

1、旋转数组 public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** 旋转数组* param n int整型 数组长度* param m int整型 右移距离* param a int整型一维数组 给定数组* return int整型一维数组*/…...

如何通过Instagram群发消息高效拓展客户?

之前小S有跟大家说过关于独立站&#xff0b;Instagram如何高效引流&#xff0c;发现大家都对Instagram的话题挺关注的。Instagram作为全球最受欢迎的社交媒体之一&#xff0c;对于许多商家和营销人员来说&#xff0c;Instagram是一个不可忽视的营销平台&#xff0c;他们可以通过…...

基于springboot实现多线程抢锁的demo

1、本代码基于定时调度和异步执行同时处理&#xff0c;如果只加异步处理&#xff0c;会导致当前任务未执行完&#xff0c;下个任务到点也不会触发执行 Scheduled(fixedRate 50_000)Asyncpublic void testThread() throws Exception{ZkLock lock new ZkLock(zkJob.getZK(), &q…...

Java I/O模型发展以及Netty网络模型的设计思想

Java I/O模型发展以及Netty网络模型的设计思想 I/O模型Java BIOJava NIOJava AIO NIO Reactor网络模型单Reactor单线程模型单Reactor多线程模型主从Reactor多线程模型 Netty通信框架 前言&#xff1a; BIO、NIO的代码实践参考&#xff1a;Java分别用BIO、NIO实现简单的客户端服…...

智能电网时代:数字孪生的崭露头角

随着科技的不断进步&#xff0c;数字孪生已经开始在电力行业崭露头角&#xff0c;为这个关键的行业带来了前所未有的机遇和潜力。本文就带大家了解一下数字孪生在哪些方面为电力行业做出改变&#xff0c;以及未来的创新应用。 首先&#xff0c;数字孪生可以提高电力系统运营效率…...

每日一题 501二叉搜素树中的众数(中序遍历)

题目 给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST 满足如下定义&a…...

测试理论与方法----测试流程第三个环节:设计测试用例

测试流程第三个环节&#xff1a;设计测试用例&#xff1a;怎么测<——>测试需求的提取&#xff1a;测什么 ### 5、测试用例 描述&#xff1a;测试用例(TestCase)&#xff1a;是一份关于【具体测试步骤】的文档&#xff0c;是为了达到最佳的测试效果或高效揭露软件中潜藏的…...

C++多态案例2----制作饮品

#include<iostream> using namespace std;//制作饮品的大致流程都为&#xff1a; //煮水-----冲泡-----倒入杯中----加入辅料//本案例利用多态技术&#xff0c;提供抽象类制作饮品基类&#xff0c;提供子类制作茶叶和咖啡class AbstractDrinking {public://煮水//冲水//倒…...

机械零件保养3d模拟演示打消客户购买顾虑

复杂机械的工作运转是复杂的&#xff0c;想要对机械有深度的理解和迭代&#xff0c;必须了解它的运转原理及参数&#xff0c;复杂机械运行原因教学存在着不可视、系统庞杂及知识点多等弊病&#xff0c;3D虚拟展示是基于web3d网页运行的三维页面&#xff0c;可以将复杂机械运行过…...

SpringBoot的自动装配源码分析

文章目录 一&#xff1a;什么是自动装配二、springboot的启动流程1.调用SpringApplication&#xff08;&#xff09;的构造方法2.执行核心run方法&#xff08;&#xff09;3.执行核心prepareContext&#xff08;&#xff09;4.执行核心refreshContext&#xff08;&#xff09;5…...

Linux常用命令——csplit命令

在线Linux命令查询工具 csplit 将一个大文件分割成小的碎片文件 补充说明 csplit命令用于将一个大文件分割成小的碎片&#xff0c;并且将分割后的每个碎片保存成一个文件。碎片文件的命名类似“xx00”&#xff0c;“xx01”。csplit命令是split的一个变体&#xff0c;split只…...

React 组件的3大属性: state

state 一、理解二、用途三、使用3.1、类初始化3.2、函数初始化 四、状态读更4.1、组件内部状态管理和数据更新4.2、state 和 props 一起使用 一、理解 组件被称为"状态机", 页面的显示是根据组件的state 属性的数据来显示。 state 是一个用于存储和管理组件内部数据的…...

vscode 上传项目到gitlab

第一步初始化项目 如果没有创建过分支&#xff08;创建分支这里不记录&#xff09;&#xff0c;默认是master分支&#xff1a; ①将所需要的上传的文件添加到暂存区&#xff0c;如图&#xff1a; ②填写一下注释信息&#xff0c;将暂存区的文件上传到本地分支&#xff08;没有创…...

[羊城杯 2020] easyphp

打开题目&#xff0c;源代码 <?php$files scandir(./); foreach($files as $file) {if(is_file($file)){if ($file ! "index.php") {unlink($file);}}}if(!isset($_GET[content]) || !isset($_GET[filename])) {highlight_file(__FILE__);die();}$content $_GE…...

QT 常用类与组件

0 思维导图 1 信息调试类&#xff08;QDebug&#xff09; #include "widget.h" #include<iostream> //printf #include<QDebug> //qDebuf using namespace std; //coutWidget::Widget(QWidget *parent): QWidget(parent) {//输出函数//使用…...

C#控制台连接Mysql数据库,有配置数据库连接字符串的配置文件

C#控制台连接Mysql数据库&#xff0c;有配置数据库连接字符串的配置文件 实现功能 读取..txt 中的配置文件&#xff0c;来初始化连接字符串让连接字符串的配置文件不存在会主动创建默认的连接字符串 注意点&#xff1a; 需要引用Newtonsoft使用mysql 代码如下 using Syst…...

PowerBuilder连接SQLITE3

PowerBuilder,一个古老的IDE,打算陆续发些相关的,也许还有人需要,内容可能涉及其他作者,但基本都是基于本人实践整理,如涉及归属,请联系. SQLite,轻型数据库,相对与PowerBuilder来说是个新事务,故发数来,以供参考. PB中使用OLE Microsoft OLE DB方式进行连接,如下 // Profile…...

Git 基本原理和常用操作

Git Git 是一个开源的分布式版本控制系统&#xff0c;可以有效、高速地处理从很小到非常大的项目版本管理。由 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开源的版本控制软件。 Git 常用操作 git 提交流程&#xff1a;工作区 -> git add 到暂存区 -> gi…...

单元测试和集成测试的区别

单元测试和集成测试是软件开发中常用的两种测试方法&#xff0c;它们的主要区别如下&#xff1a; 范围不同&#xff1a;单元测试关注于对软件中的最小功能单元进行测试&#xff0c;通常是对独立的函数、方法或类进行测试。而集成测试则更加综合&#xff0c;涉及多个模块、组件或…...

node基础概念

前言&#xff1a;可以让别人访问我们的网页&#xff0c;可以开发服务端应用、工具类应用、桌面端应用&#xff08;electron&#xff09; 1. 计算机基础 概念&#xff1a;CPU 内存 硬盘 主板 显卡 2. 进程和线程 概念&#xff1a;进程是一个程序的执行&#xff0c;线程组合形…...

ArcGIS Maps SDK for JS(二):MapView简介----创建2D地图

文章目录 1 AMD 引用 ArcGIS Maps SDK for JavaScript2 加载相应模块3 创建地图4 创建 2D 视图 view5 确定页面内容6 CSS 样式7 完整代码 本教程使用 AMD 模块&#xff0c;指导您如何在二维地图视图中创建一个简单的地图。 1 AMD 引用 ArcGIS Maps SDK for JavaScript 在 <…...