首页 > 其他分享 >Sentinel规则Pull模式持久化

Sentinel规则Pull模式持久化

时间:2023-06-02 20:32:37浏览次数:53  
标签:Pull 持久 String alibaba sentinel Sentinel import com public


阅读文本大概需要3分钟。

      前一篇【使用Nacos存储Sentinel的限流规则】讲了基于Nacos的Push模式持久化,这里讲下基于本地文件的Pull模式持久化。在网上看到一篇讲这个讲得不错的:

从官网的说明

https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel#Pull模式

有如下一张图,总觉得例子欠缺些什么??

Sentinel规则Pull模式持久化_java

琢磨一下,发现原来无论官方的例子,还是网友的例子都没有结合Sentinel讲解规则的Pull。现在开始操作,按照官方的步骤开始操作:

https://github.com/alibaba/Sentinel/wiki/动态规则扩展

在微服务的pom.xml文件引入

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-extension</artifactId>
    <version>x.y.z</version>
</dependency>

不知道哪里出了问题,到最后也没有搞通?而且还有如下疑问

  • 微服务到底连接哪个Sentinel服务?如果没有配置,可能可以连接默认的Sentinel服务
  • 如果Sentinel服务的ip和port变了呢?如何配置?也没有找到具体说明?

带着这两个疑问开始学习之旅。因为基于springboot和springcloud讲解,所有Spring Cloud Alibaba这么好的技术,为什么不用呢?

0x01:新建项目olive-pull-sentinel-datasource

  • pom.xml文件引入
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sentinel</groupId>
    <artifactId>olive-pull-sentinel-datasource</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <name>olive-pull-sentinel-datasource</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>1.7.1</version>
        </dependency>


          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version> 1.2.68</version>
        </dependency>

    </dependencies>
</project>
  • 编写如下代码

常量类,主要是定义规则文件的目录和名字

package com.sentinel.olive.file;

import java.util.HashMap;
import java.util.Map;

public class PersistenceRuleConstant {

    /**
     * 存储文件路径
     */
    public static final String storePath = System.getProperty("user.home")+"\\sentinel\\rules\\";

    /**
     * 各种存储sentinel规则映射map
     */
    public static final Map<String,String> rulesMap = new HashMap<String,String>();

    //流控规则文件
    public static final String FLOW_RULE_PATH = "flowRulePath";

    //降级规则文件
    public static final String DEGRAGE_RULE_PATH = "degradeRulePath";

    //授权规则文件
    public static final String AUTH_RULE_PATH = "authRulePath";

    //系统规则文件
    public static final String SYSTEM_RULE_PATH = "systemRulePath";

    //热点参数文件
    public static final String HOT_PARAM_RULE = "hotParamRulePath";

    static {
        rulesMap.put(FLOW_RULE_PATH,storePath+"flowRule.json");
        rulesMap.put(DEGRAGE_RULE_PATH,storePath+"degradeRule.json");
        rulesMap.put(SYSTEM_RULE_PATH,storePath+"systemRule.json");
        rulesMap.put(AUTH_RULE_PATH,storePath+"authRule.json");
        rulesMap.put(HOT_PARAM_RULE,storePath+"hotParamRule.json");
    }
}

文件操作类,如果规则文件不存在就创建对应的目录和对应的规则文件

package com.sentinel.olive.file;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RuleFileUtils {

     private static final Logger logger = LoggerFactory.getLogger(RuleFileUtils.class);

    /**
     * 方法实现说明:若路径不存在就创建路径
     * @param filePath:文件存储路径
     */
    public static void mkdirIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if(!file.exists()) {
            logger.info("创建Sentinel规则目录:{}",filePath);
            file.mkdirs();
        }
    }


    /**
     * 方法实现说明:若文件不存在就创建路径
     * @param ruleFileMap 规则存储文件
     */
    public static void createFileIfNotExits(Map<String,String> ruleFileMap) throws IOException {

        Set<String> ruleFilePathSet = ruleFileMap.keySet();

        Iterator<String> ruleFilePathIter = ruleFilePathSet.iterator();

        while (ruleFilePathIter.hasNext()) {
            String ruleFilePathKey = ruleFilePathIter.next();
            String ruleFilePath  = PersistenceRuleConstant.rulesMap.get(ruleFilePathKey).toString();
            File ruleFile = new File(ruleFilePath);
            if(ruleFile.exists()) {
                logger.info("创建Sentinel 规则文件:{}",ruleFile);
                ruleFile.createNewFile();
            }
        }
    }
}

规则的编码和解码操作类

package com.sentinel.olive.file;

import java.util.List;

import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

public class RuleListParserUtils {

    /**
     * 流控列表解析器
     */
    public static final Converter<String, List<FlowRule>> flowRuleListParser = new Converter<String, List<FlowRule>>() {
        @Override
        public List<FlowRule> convert(String source) {
            return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
            });
        }
    };

    /**
     * 流控列表 编码器
     */
    public static final Converter<List<FlowRule>, String> flowRuleEnCoding = new Converter<List<FlowRule>, String>() {
        @Override
        public String convert(List<FlowRule> source) {
            return JSON.toJSONString(source);
        }
    };

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

    public static final Converter<List<DegradeRule>, String> degradeRuleEnCoding = new Converter<List<DegradeRule>, String>() {
        @Override
        public String convert(List<DegradeRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source,
            new TypeReference<List<SystemRule>>() {
            });

    public static final Converter<List<SystemRule>, String> systemRuleEnCoding = new Converter<List<SystemRule>, String>() {
        @Override
        public String convert(List<SystemRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON
            .parseObject(source, new TypeReference<List<AuthorityRule>>() {
            });


    public static final Converter<List<AuthorityRule>, String> authorityRuleEnCoding = new Converter<List<AuthorityRule>, String>() {
        @Override
        public String convert(List<AuthorityRule> source) {
            return JSON.toJSONString(source);
        }
    };

    public static final Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON
            .parseObject(source, new TypeReference<List<ParamFlowRule>>() {
            });


//    public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = new Converter<List<ParamFlowRule>, String>() {
//        @Override
//        public String convert(List<ParamFlowRule> source) {
//            return JSON.toJSONString(source);
//        }
//    };

    public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = source -> encodeJson(source);

    private static <T> String encodeJson(T t) {
        return JSON.toJSONString(t);
    }

}

具体pull模式操作类

package com.sentinel.olive.file;

import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
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;

public class PullModeLocalFileDataSource implements InitFunc {

    private static final Logger logger = LoggerFactory.getLogger(PullModeLocalFileDataSource.class);

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    @Override
    public void init() throws Exception {
        logger.info("time:{}读取配置", sdf.format(new Date()));
        try {
            // 创建文件存储目录(若路径不存在就创建路径)
            RuleFileUtils.mkdirIfNotExits(PersistenceRuleConstant.storePath);
            // 创建规则文件()
            RuleFileUtils.createFileIfNotExits(PersistenceRuleConstant.rulesMap);
            // 处理流控规则逻辑
            dealFlowRules();
            // 处理降级规则
            dealDegradeRules();
            // 处理系统规则
            dealSystemRules();
            // 热点参数规则
            dealParamFlowRules();
            // 授权规则
            dealAuthRules();
        } catch (Exception e) {
            logger.error("错误原因:{}", e);
        }

    }

    /**
     * 方法实现说明:处理流控规则逻辑
     */
    private void dealFlowRules() throws FileNotFoundException {
        String ruleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.FLOW_RULE_PATH).toString();
        // 创建流控规则的可读数据源
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(ruleFilePath,
                RuleListParserUtils.flowRuleListParser);
        // 将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<List<FlowRule>>(ruleFilePath,
                RuleListParserUtils.flowRuleEnCoding);

        // 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
        // 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
    }

    // 处理降级规则
    private void dealDegradeRules() throws FileNotFoundException {
        String degradeRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.DEGRAGE_RULE_PATH).toString();
        // 降级规则
        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath,
                RuleListParserUtils.degradeRuleListParser);
        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath,
                RuleListParserUtils.degradeRuleEnCoding);
        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);

    }

    // 处理系统规则
    private void dealSystemRules() throws FileNotFoundException {
        String systemRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.SYSTEM_RULE_PATH).toString();
        // 系统规则
        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(systemRulePath,
                RuleListParserUtils.systemRuleListParser);
        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
        WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath,
                RuleListParserUtils.systemRuleEnCoding);
        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
    }

    // 热点参数规则
    private void dealParamFlowRules() throws FileNotFoundException {
        String paramFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.HOT_PARAM_RULE).toString();
        // 热点参数规则
        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
                paramFlowRulePath, RuleListParserUtils.paramFlowRuleListParser);
        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,
                RuleListParserUtils.paramFlowRuleEnCoding);
        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
    }

    private void dealAuthRules() throws FileNotFoundException {
        String authFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.AUTH_RULE_PATH).toString();
        // 授权规则
        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(authFlowRulePath,
                RuleListParserUtils.authorityRuleListParser);
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authFlowRulePath,
                RuleListParserUtils.authorityRuleEnCoding);
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
    }
}

编写了以上代码就可以,通过SPI扩展机制进行扩展,在微服务工程 olive-pull-sentinel-datasource的resources目录下创建META-INF/services目录,并新建文件名为com.alibaba.csp.sentinel.init.InitFunc文件。内容是PullModeLocalFileDataSource类全路径类名

Sentinel规则Pull模式持久化_maven_02

0x02:配置文件application.yml

看到这张图总有解决了以上的疑问了,提供了配置项,配置Sentinel服务对应的ip和端口

Sentinel规则Pull模式持久化_java_03

0x03:创建测试控制器和springboot启动类

测试控制器

package com.sentinel.olive.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/getUser")
    public Map<String, Object> getUser() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", "000000");
        result.put("message", "ok");
        return result;
    }
}

springboot启动类

package com.sentinel.olive;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

0x04:启动并测试验证

启动服务

  • sentinel-dashboard服务
  • olive-pull-sentinel-datasource微服务

验证

  • sentinel-dashboard创建规则,olive-pull-sentinel-datasource微服务检测到sentinel-dashboard变化
  • 修改json规则文件的规则,sentinel-dashboard检测到json规则编码

访问微服务的http://localhost:8866/getUser接口

Sentinel规则Pull模式持久化_spring boot_04

访问sentinel-dashboard服务:http://127.0.0.1:8080/

Sentinel规则Pull模式持久化_java_05

创建流控规则

Sentinel规则Pull模式持久化_spring boot_06

olive-pull-sentinel-datasource检测到流控规则的变化并产生flowRule.json文件

Sentinel规则Pull模式持久化_java_07

修改流控规则文件json

Sentinel规则Pull模式持久化_spring_08

sentinel-dashboard查看规则的变化

Sentinel规则Pull模式持久化_java_09

关注我

每天进步一点点

Sentinel规则Pull模式持久化_java_10


标签:Pull,持久,String,alibaba,sentinel,Sentinel,import,com,public
From: https://blog.51cto.com/u_13538361/6404936

相关文章

  • Sentinel控制台监控数据持久化到MySQL数据库
    阅读文本大概需要3分钟。    根据官方wiki文档,Sentinel控制台的实时监控数据,默认仅存储5分钟以内的数据。如需持久化,需要定制实现相关接口。https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel给出了指导步骤:自行扩展实现MetricsRepository接口;注册成......
  • git pull 和push讲解:016
    pull和push大致流程:(将远程仓库同步到本地仓库)>(在本地仓库修改并提交)>(推送修改内容到远程仓库) 1.首先创建一个文件夹,打开GitBash终端,cd到这个文件夹内 2.将(远程仓库)的克隆到这个文件夹内:gitclone远程仓库连接 3.打开终端,然后cd进入项目文件 4.然后建立与(......
  • Sentinel整合Spring Cloud Gateway、Zuul详解
    Sentinel支持对SpringCloudGateway、Zuul等主流的APIGateway进行限流。编辑切换为居中添加图片注释,不超过140字(可选)Sentinel1.6.0引入了SentinelAPIGatewayAdapterCommon模块,此模块中包含网关限流的规则和自定义API的实体和管理逻辑:GatewayFlowRule:网关限流规......
  • Spring Cloud Alibaba Sentinel实现熔断限流代码示例
    SpringCloudAlibabaSentinel介绍SpringCloudAlibabaSentinel是一个面向分布式服务架构的流量控制组件,是SpringCloudAlibaba的核心组件之一。主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。代码示例以下是一个使用SpringC......
  • redis持久化
    一、Redis持久化,两种方案RDB--->存的是数据,恢复数据直接加载数据到内存中,速度快,丢失数据风险大redisdatabasebackupfile(redis数据备份文件),即在关闭redis时,执行save命令,把所有数据都记录到磁盘中,保存。执行时机:--1.手动执行--2.正常关机用save命令--3.自动触......
  • Java 进阶 - SpringJPA 持久层框架
    参考资料https://spring.io/projects/spring-data-jpa介绍SpringDataJPA是Spring基于ORM(ObjectRelationalMapping)框架、JPA规范的基础上封装的一套JPA应用框架,底层使用了Hibernate的JPA技术实现,可使开发者用极简的代码即可实现对数据的访问和操作。它提供了......
  • vue中使用vant中PullRefresh 下拉刷新踩坑
    问题PullRefresh的内容未填满屏幕时,只有一部分区域可以下拉:<template><divclass="appCon"><van-pull-refreshclass="pageRefresh"v-model="isLoading"success-text="刷新成功"@refresh="onRefre......
  • redis 持久化
    为什么需要持久化,持久化是什么redis是基于内存的所以速度快,没有与磁盘交互。但是缺点就是断电或宕机数据就没了,这是不可接受的。持久化就是把内存的数据也存在磁盘上,用于redis重启后时恢复数据。两种方式RDB和AOFRDB快照操作,持久化当前内存中的数据。分为手动触发和自动......
  • redis持久化配置
    redis有两种持久化方式:RDB和AOF。具体差别跟优缺点可参考redis数据的两种持久化方式对比,本篇只介绍这两种方式怎么配置RDB配置方式默认情况下,是快照RDB的持久化方式,将内存中的数据以快照的方式写入二进制文件中,默认的文件名是dump.rdbredis.conf默认配置:save9001save30010sav......
  • 关于redis的描述、数据结构、持久化学习笔记
    前言本文围绕面试问题、redis学习记录。本文是个人的笔记,会有遗漏或含糊的地方。描述下redisredis是一款非关系型数据库,它是以key-value的形式存在数据,因为它的数据在内存中所以它的读写速度极高。当然它支持持久化,将数据以二进制形式或者以命令的形式持久化到磁盘。然后......