Sentinel限流熔断工具的使用以及持久化(超详细)


最近公司交付了一项任务,使用阿里巴巴组件sentinel进行限流和熔断,前后经历了几天的开发和部署,最终成功上线,途中也踩了一些坑,查了不少资料,会在文章中写明解决的办法,方便大家一次过。

sentinel部署

添加依赖

这部分比较简单,我的项目是springboot,直接在pom.xml文件中添加依赖。

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

这里遭遇了第一个坑,就是依赖引不进来,通过查阅资料,在pom.xml再次添加以下代码,成功引入依赖。

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

这里大家注意下,这个version的版本2.2.3里面有sentinel的版本号,含义是客户端的版本号,其中客户端版本号要跟dashbord版本号相近,不然会出现其他问题,关于版本不一致的坑我等会再说。

点进去可以看到客户端版本是1.8.0

这里可以看到控制台版本是1.8.5

添加配置

依赖引入之后,我们在application.properties这个配置文件中增加两行配置。

spring.cloud.sentinel.transport.dashboard=127.0.0.1:9192
spring.cloud.sentinel.enabled=true

第一个配置是自己的控制台的地址,后面的端口是自己配置的,我用的9192,默认8080

运行客户端

我们要去官方下载控制台的jar文件,下载地址
注意版本要跟前面的客户端版本接近,我当时用的最新版本1.8.5。
下载好了之后,开始在本地用java命令启动。

java -jar -Dserver.port=9192 sentinel-dashboard-1.8.5.jar

运行成功之后,就可以打开客户端了。
账号和密码都是sentinel
注意客户端是懒加载,如果没有任何东西显示,你随便运行一个接口,就能看到了。
控制台
簇点链路
点击列表视图,更方便的管理接口。
至于每个功能是做什么用的,我这里就不赘述了,你们可以看其他文档了解,我只教大家怎么成功的部署起来。
这里教大家怎么用这个东西

版本不一致带来的坑

通过设置上面的流控和熔断,你会发现自己的配置生效了,如果你发现你的配置无法生效,特别是熔断的阈值,设置了小数,但实际没有生效,那就恭喜你步入了第二个坑;如果生效成功,这段直接跳过。
阈值配置
不生效就是上面说的,版本不一致,导致的BUG,解决版本就是版本对应好,我之前客户端版本是1.6.3,所以没生效。

不能持久化

第三个坑来了,你会发现,这个工具是基于内存的,每次服务重启后,你配置的规则就会消失,这还玩个der!
那么,有什么方法,能够让服务重启后,还能保持原来的配置呢?当然有!
网上的攻略提供了两个持久化的方法
1.配置保留在服务器本地文件,随时读写。
2.使用nacos读写配置
如果你的项目本身就是nacos做配置中心,那很简单,用nacos,网上攻略很多,我不赘述了。
我要讲的是写本地的配置,这种适用于那种不是nacos配置的服务。

sentinel持久化

添加配置

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

添加service文件

这个文件不需要加@service注解,可以直接用,ruleDir是文件的读写位置,可以修改为你喜欢的地址。


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 {

    @Override
    public void init() throws Exception {
        String ruleDir = "/opt/sentinel/rules";
//        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);
    }

}

添加引用

在项目的resource文件夹下面添加这样一个文件
添加引用

注意!!!
这个文件夹和文件的名字都不能有任何错误!否则就会失败,文件名的内容是上面那个类的地址。
之前我就是因为看了别人的攻略 把META-INF写成了META_INF,半天不生效,气死了!
文件名是com.alibaba.csp.sentinel.init.InitFunc 没有任何后缀。

注意

还需要注意的地方是,你的项目是否引用到这个resource了,不然引用不到同样会失败。
引用
一般有这样的配置,说明引用到resource了。

总结

做完这么多,持久化就成功了,你从控制台修改配置,能够直接写入到文件中。
文件格式
文件格式是这样的。
你直接修改文件,很快控制台也能读到,并且立刻生效。
并且重启服务,配置还是在的,说明持久化生效了。

还有需要注意的是,有些运维部署这个项目,每次重启后,这个文件夹地址会刷新,导致文件不见了,有一种做法是添加映射卷,将实体文件夹映射到服务器文件夹中,这样每次这个文件夹不会刷新,会读取实体文件夹,具体做法我不会,是我们公司运维操作的。

攻略暂时就做到这里,有任何不懂的可以在评论区留下您的意见。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值