Spring Cloud Alibaba - Sentinel入门案例(六)(补充使用(一) Sentinel规则持久化 / @SentinelResource的使用 )

Spring Cloud Alibaba - Sentinel入门案例(六)(补充使用 (一) Sentinel规则持久化 / @SentinelResource的使用 )

回溯

前面的博文已经讲述了关于Sentinel的简单使用,但是还是有一些需要功能点没有覆盖,这边在进行简单分析。

正文

Sentinel规则持久化

在之前的博文中,有一个遗留的问题,就是无论设定了什么规则,当项目重启的时候,规则就消失了,需要重新配置,这是因为配置的规则并没有持久化文件,而是存在内存中,所以当项目启动的时候之前配置的都会消失。

本地文件数据源会定时轮询文件的变更,读取规则。这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。

首先需要新增一个配置类,配置本地持久化文件的存放路径等等。

public class FilePersistence implements InitFunc {
    
    
    @Value("spring.application:name")
    private String appcationName;

    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>>() {
    
    
                    }
            );

    @Override
    public void init() throws Exception {
    
    
        String ruleDir = System.getProperty("user.home") + "/sentinelrules/" + appcationName;
        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 void mkdirIfNotExits(String filePath) {
    
    
        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
在这里插入图片描述
里面存放刚才编写的配置类的路径:

例如:com.example.nacos.demo.config.FilePersistence
在这里插入图片描述
配置完毕,重启项目,这时候就发现,设置的规则,之后重启都可以加载,证明持久化成功。

ps(sentinel是懒加载,所以重启项目,还是需要访问一下,之前的规则才能重新展示)

@SentinelResource的使用

在定义了资源点之后,我们可以通过Dashboard来设置限流和降级策略来对资源点进行保护。同时还能通过@SentinelResource来指定出现异常时的处理策略。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。其主要参数如下:

属性 作用
value 资源名称
entryType entry类型,标记流量的方向,取值IN/OUT,默认是OUT
blockHandler 处理BlockException的函数名称,函数要求:1. 必须是 public 2.返回类型 参数与原方法一致 3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置blockHandlerClass ,并指定blockHandlerClass里面的方法。
blockHandlerClass 存放blockHandler的类,对应的处理函数必须static修饰。
fallback 用于在抛出异常的时候提供fallback处理逻辑。fallback函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。函数要求:1. 返回类型与原方法一致 2. 参数类型需要和原方法相匹配 3. 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定fallbackClass里面的方法。
fallbackClass 存放fallback的类。对应的处理函数必须static修饰。
defaultFallback 用于通用的 fallback 逻辑。默认fallback函数可以针对所有类型的异常进行处理。若同时配置了 fallback 和 defaultFallback,以fallback为准。函数要求:1. 返回类型与原方法一致 2. 方法参数列表为空,或者有一个 Throwable 类型的参数。3. 默认需要和原方法在同一个类中。若希望使用其他类的函数,可配置fallbackClass ,并指定 fallbackClass 里面的方法。
exceptionsToIgnore 指定排除掉哪些异常。排除的异常不会计入异常统计,也不会进入fallback逻辑,而是原样抛出。
exceptionsToTrace 需要trace的异常

定义限流和降级后的处理方法

方式一

把方法定义在资源类中
例如:

@Service
@Slf4j
public class MessageServiceImpl implements MessageService {
    
    

    int throwableCount = 0;

    @Override
    @SentinelResource(value = "message", blockHandler = "blockHandler", fallback = "fallback")
    public String message() {
    
    
        throwableCount++;
        if (throwableCount % 3 == 0) {
    
    
            throw new RuntimeException();
        }
        return "success";
    }

    //BlockException时进入的方法
    public String blockHandler(BlockException ex) {
    
    
        log.error("{}", ex);
        return "接口被限流或者降级了...";
    }

    //Throwable时进入的方法
    public String fallback(Throwable throwable) {
    
    
        log.error("{}", throwable);
        return "接口发生异常了...";
    }

}

在sentinel控制台设置一个简单的流控规则。
在这里插入图片描述

请求后,根据控制台的日志,证明了,当发生熔断和异常的时候有进入到对应的方法里面。

在这里插入图片描述
在这里插入图片描述

方式二

将限流和降级方法外置到单独的类中。

@Slf4j
public class MessageServiceBlockHandlerClass {
    
    

    //注意这里必须使用static修饰方法
    public static String blockHandler(BlockException ex) {
    
    
        log.error("{}", ex);
        return "接口被限流或者降级了...";
    }

}
@Slf4j
public class MessageServiceFallbackClass {
    
    

    //注意这里必须使用static修饰方法
    public static String fallback(Throwable throwable) {
    
    
        log.error("{}", throwable);
        return "接口发生异常了...";
    }

}
@Service
@Slf4j
public class MessageServiceImpl implements MessageService {
    
    

    int throwableCount = 0;

    @Override
    @SentinelResource(value = "message", blockHandlerClass = MessageServiceBlockHandlerClass.class,blockHandler = "blockHandler", fallbackClass = MessageServiceFallbackClass.class,fallback = "fallback")
    public String message() {
    
    
        throwableCount++;
        if (throwableCount % 3 == 0) {
    
    
            throw new RuntimeException();
        }
        return "success";
    }
    
}

测试步骤和上面一致。
在这里插入图片描述

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_29064815/article/details/107163048