当前位置:   article > 正文

SCA - Sentinel入门实战_sca-sentinel

sca-sentinel

实战

环境

Sentinel Dashboard
System(uname -a): Linux VM-0-15-centos 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
Sentinel Dashboard Version: sentinel-dashboard-1.8.2

Demo Application:
System: macOS 10.14.6
JDK: 1.8.0_251
Spring Boot:2.2.13.RELEASE
Spring Cloud:Hoxton.SR12
Spring Cloud Alibaba: 2.2.5.RELEASE

Sentinel Dashboard 安装

单机版点这里

java -Dserver.port=10000 -Dcsp.sentinel.dashboard.server=localhost:10000 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar
  • 1

集群版:需二次开发,见:Sentinel Dash board 多控制台部署和主从问题 #1567 或使用企业级的 Sentinel 控制台 (AHAS Sentinel)

集成Sentinel

项目:wfbi-sentinel

pom依赖

 <!-- sentinel -->
 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
 </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

添加配置

spring:
  application:
    name: sentinel-service
  cloud:
    # sentinel config
    sentinel:
      transport:
        dashboard: localhost:10000
        port: 8719
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Spring Cloud 自动集成

sentinel自动集成Spring Cloud,自动生成一些默认资源。

@RestController
@RequestMapping("/flow")
@Slf4j
public class FlowController {

    /**
     * 默认接口,主流框架的默认适配
     *
     * @return
     */
    @GetMapping("")
    public String defaultResource() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "sentinel defaultResource";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

访问:curl http://localhost:10013/flow,查看dashboard簇点链路。
在这里插入图片描述

资源定义

我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:

流控规则

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

阈值类型

分为QPS限流线程数限流

QPS限流

定义资源

/**
 * 注解方式定义资源
 *
 * @return
 */
@RequestMapping("/annotation")
@SentinelResource(value = "annotationResource", blockHandler = "blockHandlerForAnnotationResource")
public String annotationResource() {
    return "annotationResource: 正常处理结果";
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public String blockHandlerForAnnotationResource(BlockException ex) {
    return "annotationResource: 限流或被降级处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

定义规则
在这里插入图片描述

上面是对资源annotationResource进行QPS限流,针对所有来源,且阈值为2。当接口请求的QPS>=2时进行限流。

  • 资源名:唯一名称,默认是请求路径,可自定义。
  • 针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制。
  • 阈值类型/单机阈值:
    • QPS(每秒请求数量): 当调用该接口的QPS达到阈值的时候,进行限流。
    • 线程数:当调用该接口的线程数达到阈值的时候,进行限流。

检验规则是否生效
执行:

ab -n 100000 -c 3 http://localhost:10013/flow/annotation
  • 1

另开终端执行:

wfbi$ curl http://localhost:10013/flow/annotation
annotationResource: 限流或被降级处理结果
  • 1
  • 2
线程数限流

在这里插入图片描述

上面是对资源annotationResource进行线程数限流,针对所有来源,且阈值为2。当接口请求的线程数>=2时进行限流。

流控模式

有三种流控模式:

  • 直接(默认):接口达到限流条件时,开启限流。
  • 关联:当关联的资源达到限流条件时,开启限流 [适合做应用让步]。
  • 链路:当从某个接口过来的资源达到限流条件时,开启限流。
关联流控模式

关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流。
比如:当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢。

资源1:exceptionResource

/**
 * 抛出异常的方式定义资源
 *
 * @return
 */
@RequestMapping("/exception")
public String exceptionResource() {
    // 1.5.0 版本开始可以利用 try-with-resources 特性
    // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
    try (Entry entry = SphU.entry("exceptionResource")) {
        // 被保护的业务逻辑
        log.info("exceptionResource: 执行业务逻辑");
    } catch (BlockException ex) {
        // 资源访问阻止,被限流或被降级
        log.error("exceptionResource: 资源访问阻止,被限流或被降级");
        // 在此处进行相应的处理操作
        return "exceptionResource: 限流或被降级异常处理结果";
    }
    return "exceptionResource: 正常处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

资源2:boolResource

/**
 * 返回布尔值方式定义资源
 *
 * @return
 */
@RequestMapping("/bool")
public String boolResource() {
    // 资源名可使用任意有业务语义的字符串
    if (SphO.entry("boolResource")) {
        // 务必保证finally会被执行
        try {
            /**
             * 被保护的业务逻辑
             */
            log.info("boolResource: 执行业务逻辑");
        } finally {
            SphO.exit();
        }
    } else {
        // 资源访问阻止,被限流或被降级
        log.error("boolResource: 资源访问阻止,被限流或被降级");
        // 在此处进行相应的处理操作
        return "boolResource: 限流或被降级处理结果";
    }
    return "boolResource: 正常处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

定义规则:
在这里插入图片描述
被限流的对象是boolResource,被限流的条件是当关联资源exceptionResource的QPS>=2。

检验规则是否生效
执行:

ab -n 100000 -t 1000 http://localhost:10013/flow/exception
  • 1

另开终端执行:

wfbi$ curl http://localhost:10013/flow/bool
boolResource: 限流或被降级处理结果
  • 1
  • 2
链路流控模式

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

增加配置禁止收敛所有URL入口Context

spring:
  cloud:
    sentinel:
      web-context-unify: false
  • 1
  • 2
  • 3
  • 4

注意: 从1.6.3 版本开始,Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效。本文使用的SCA版本通过上述配置禁止收敛没有问题,网上看到有使用老版本的需要添加配置类,自己构建CommonFilter实例来禁止收敛所有URL的入口context

ChainService::trace定义为资源traceResource

@SentinelResource(value = "traceResource", blockHandler = "traceHandler")
public String trace(String path){
    log.info("Invoke ChainService::trace, path=" + path);
    return "traceResource: 正常处理结果, path=" + path;
}

// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public String traceHandler(String path, BlockException ex) {
    log.error("traceResource: 限流或被降级处理结果, path=" +path);
    return "traceResource: 限流或被降级处理结果, path=" + path;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

FlowController中定义两个接口方法都调用ChainService::trace

private final ChainService chainService;

/**
 * 链路流控模式测试方法1
 *
 * @return
 */
@RequestMapping("/trace1")
public String tracePath1() {
    String path = "/flow/trace1";
    return chainService.trace(path);
}

/**
 * 链路流控模式测试方法2
 *
 * @return
 */
@RequestMapping("/trace2")
public String tracePath2() {
    String path = "/flow/trace2";
    return chainService.trace(path);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Sentinel Dashboard定义规则

在这里插入图片描述
以上含义是当资源traceResource的QPS>=2时出发流控,注意被限制的资源是入口资源即/flow/trace1,也就是说其他入口如/flow/trace2不会被限制,可以正常执行业务逻辑。

检验规则是否生效

ab test开启开启对接口/flow/trace2的不间断访问,QPS要大于等于2。此时通过浏览器去访问/flow/trace1,返回如下:
在这里插入图片描述
说明trace1接口已经被限流了,说明其他入口的访问资源traceResource的QPS已满足>=2,从而触发针对trace1的限制。

流控效果

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

降级规则

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

  • 慢调用比例: 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例: 当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

慢比例调用

定义FallBackController::fallback1为资源

/**
 * 慢调用比例熔断测试
 *
 * @return
 */
@RequestMapping("/1")
@SentinelResource(blockHandler = "blockHandlerForfallback1")
public String fallback1() {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info("fallback1: 正常处理结果");
    return "fallback1: 正常处理结果";
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public String blockHandlerForfallback1(BlockException ex) {
    log.error("fallback1: 限流或被降级处理结果");
    return "fallback1: 限流或被降级处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

通过TimeUnit.SECONDS.sleep(1)模拟耗时。

定义降级熔断规则
在这里插入图片描述

上面配置表示,如果在S(统计时长)之内,有超过1个的请求且这些请求中响应时间>最大RT请求数量比例>10%,就会触发熔断,在接下来的10s之内都不会调用真实方法,直接走降级方法。

检验规则是否生效
在这里插入图片描述

异常数

定义FallBackController::fallback2为资源

/**
 * 异常数熔断测试
 *
 * @return
 */
@RequestMapping("/2")
@SentinelResource(blockHandler = "blockHandlerForfallback2")
public String fallback2() {
    log.error("fallback2: 抛出业务异常");
    throw new RuntimeException("fallback2: 抛出业务异常");
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public String blockHandlerForfallback2(BlockException ex) {
    log.error("fallback2: 限流或被降级处理结果");
    return "fallback2: 限流或被降级处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

定义降级熔断规则
在这里插入图片描述
上面配置表示,如果在1s之内,有超过1个的请求,请求中超过1个请求出现异常就会触发熔断,在接下来的10s之内都不会调用真实方法,直接走降级方法。

检验规则是否生效
在这里插入图片描述

热点规则

热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制。
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制.

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

定义HotSpotController::hostspot1为资源

/**
 * 热点参数测试
 *
 * @return
 */
@RequestMapping("/1")
@SentinelResource(blockHandler = "blockHandlerForhostspot1")
public String hostspot1(String param) {
    log.info("hostspot1: 正常处理结果, param=" + param);
    return "hostspot1: 正常处理结果";
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public String blockHandlerForhostspot1(String param, BlockException ex) {
    log.error("hostspot1: 限流或被降级处理结果, param=" + param);
    return "hostspot1: 限流或被降级处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

定义热点参数规则

首先新增热点规则
在这里插入图片描述
然后编辑热点规则
在这里插入图片描述
这里应该有个bug,在指定java.lang.String类型时一直不生效。后来先设置成int类型保存下来,再去修改编辑才可以

上面参数索引是指参数的位置,从0开始。对应到方法上就是参数param。也就是param值为a时且QPS>=2时触发限制。当参数为其它值比如b时不管QPS是多少都会被限制。

检验规则是否生效

通过ab test或其它工具使请求的QPS>=2,此时访问/hotspot/1?param=a,如下:
在这里插入图片描述
此时访问/hotspot/1?param=b,如下:

在这里插入图片描述

授权规则

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过:

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

黑名单

定义资源(默认生成)

@RequestMapping("/1")
public String auth1(String origin){
    log.info("auth1: 正常处理结果, origin=" + origin);
    return "auth1: 正常处理结果";
}
  • 1
  • 2
  • 3
  • 4
  • 5

来源参数解析

@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        /**
         *  定义从请求的什么地方获取来源信息
         *  比如我们可以要求所有的客户端需要在请求头中携带来源信息
         */
        String origin = request.getParameter("origin");
        return origin;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

定义黑名单规则

在这里插入图片描述
以上代表针对资源/auth/1进行黑名单限制,当来源为aservcie进行限制,其它类型如bservice时不做限制。

检验规则是否生效

请求url:http://localhost:10013/auth/1?origin=aservice
在这里插入图片描述
请求url:http://localhost:10013/auth/1?origin=bservice
在这里插入图片描述

系统规则

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

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发。
  • 系统容量。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
  • CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护。

统一异常处理

两种方式:

  • @ControllerAdvice结合@ExceptionHandler进行全局异常处理
  • 实现BlockExceptionHandler接口并实现handle方法进行统一异常处理

Sentinel规则持久化

Sentinel 规则默认是存放在内存中,极不稳定,所以需要将其持久化。可通过DataSource 扩展将规则存储在文件、数据库或者配置中心当中实现持久化。

DataSource 扩展常见的实现方式有:

  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

拉模式-文件数据源

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

首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。

持久化处理类

// InitFunc SPI 扩展接口
public class FilePersistence implements InitFunc {
    @Override
    public void init() throws Exception {
        String ruleDir = System.getProperty("user.home") + "/sentinel-rules/" + "wfbi-sentinel";
        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);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125

推模式-Nacos

要下载Nacos Dashboard源代码进行改造后才可以支持Sentinel和Nacos之间的双向读写。

详见Sentinel1.8.0配置持久化到Nacos(基于push模式)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/889157
推荐阅读
  

闽ICP备14008679号