Sentinel持久化到本地文件

首先去Sentinel官网上,将它的源码进行下载,因为在它源码上进行修改,当然如果觉得源码不方便,也可以直接下载它官网上的jar包

Sentinel官方地址

https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D

Sentinel下载地址

https://github.com/alibaba/Sentinel/releases

将源码下载下来后,我们向进入dashboard模块(Sentinel控制台模块),配置文件默认为properties格式,我这里自定义改成了yml格式,并自定义端口号为8888,防止8080与其他服务端口冲突启动控制台:localhost:8888 如下界面,可以看到我们可以配置多个规则

上面我们的Sentinel Server端基本就改造完成了,接下来开始配置我们的客户端 我们先在客户端添加Sentinel依赖

<!--springboot 整合 sentinel框架-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel</artifactId>
    <version>0.9.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

接下来添加Sentinel的本地文件持久化代码,代码具体啥意思,注释都有写到了

/**
 * @Author:
 * @Date: 2020/3/26 22:00
 * @Description: klm
 */
public class DataSourceInitFunc implements InitFunc {

    @Override
    public void init() throws Exception {
        // TIPS: 持久化在本地的目录,如果你对这个路径不喜欢,可修改为你喜欢的路径
        String ruleDir = System.getProperty("user.home") + "/sentinel/order/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 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
        // 这样当规则文件发生变化时,就会更新规则到内存
        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>> 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);
    }
}

接下我们进入resources目录复制

1.新建META-INF目录
META-INF

2.然后在META-INF目录新建services目录
services

3.在services目录下,新建初始化文件,文件的内容,就是配置文件持久化代码的路径地址
com.alibaba.csp.sentinel.init.InitFunc

修改application.yml配置,在配置里面我们需要连接Sentinel控制台地址,定时向控制台发送心跳,判断服务是否健康状态复制

spring:
  application:
    name: cluster_user_sentinel
  cloud:
    #sentinel注册地址
    sentinel:
      transport:
        dashboard: localhost:8888 #Sentinel 控制台地址
        port: 8720 #客户端监控API的端口
      eager: true #取消Sentinel控制台懒加载
      log:
        dir: ./logs # 默认值${home}/logs/csp/
        switch-pid: true # 日志带上线程id

然后在我们的在项目中,创建一个接口,并对这个接口实现降级等操作

 接下来我们开始启动项目看看效果 如下图,可以看到我们的服务,已经注册Sentinel里,控制台已经能显示到

现在对刚刚创建的接口,实现流控操作

资源名:就是接口 SentinelResource注解

来源:默认default即可

阈值类型:

qps:每秒钟运行N个请求进来

线程数:每秒钟N隔线程处理

阈值:自定义的值

集群:因为我们是单机的,所以就不用选集群了

请求接口,一秒请求了两次,现在就已经限流了 但是英文返回出去,非常不友好,所以我们可以自定义返回内容出去

抽出公共的返回错误码

public enum ResponseCode {
    success(200, "请求成功"),
    fail(400, "请求失败"),
    error(500, "服务端错误"),
    serviceFuse(700, "请求熔断,稍后重试"),
    serviceFlow(701, "请求限流,稍后重试"),
    serviceHotspot(702, "请求热点参数限流,稍后重试"),
    serviceSystem(703, "请求触发系统保护规则,稍后重试"),
    serviceRules(704, "请求Sentinel授权规则不通过,稍后重试"),
    unkown(999, "未知类型"),
    ;

    private int code;
    private String desc;

    ResponseCode(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public static ResponseCode getByCode(int code) {
        for (ResponseCode responseCode : ResponseCode.values()) {
            if (responseCode.code() == (code)) {
                return responseCode;
            }
        }
        return unkown;
    }

    public int code() {
        return this.code;
    }

    public String desc() {
        return this.desc;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}


################################################

public class CommonResult<T> implements Serializable {

    public CommonResult() {
    }

    public CommonResult(T t) {
        this(ResponseCode.success.code(), null, t);
    }

    public CommonResult(int code, T t) {
        this(code, null, t);
    }

    public CommonResult(int code, String msg, T t) {
        this.code = code;
        this.msg = msg;
        this.data = t;
    }

    /*错误码*/
    private int code = ResponseCode.success.code();
    /*提示信息*/
    private String msg = "";
    /*具体的内容*/
    private T data = null;

    public CommonResult success() {
        return this;
    }

    public CommonResult success(T t) {
        this.msg = "请求成功";
        this.data = t;
        return this;
    }

    public CommonResult success(int code, T t) {
        this.code = code;
        this.msg = "请求成功";
        this.data = t;
        return this;
    }

    public CommonResult success(int code, String msg, T t) {
        this.code = code;
        this.msg = msg;
        this.data = t;
        return this;
    }

    public CommonResult failed() {
        this.code = ResponseCode.error.code();
        this.msg = "请求成功,未查询到数据";
        return this;
    }

    public CommonResult failed(int code, T t) {
        this.code = code;
        this.msg = "请求成功";
        return this;
    }

    public CommonResult failed(int code, String msg, T t) {
        this.code = code;
        this.msg = msg;
        this.data = t;
        return this;
    }

    public CommonResult failed(String msg) {
        this.code = ResponseCode.error.code();
        this.msg = msg;
        return this;
    }

    public CommonResult saveSuccess(int num) {
        this.msg = String.format("成功保存%s条数据", num);
        return this;
    }

    public CommonResult editSuccess(int num) {
        this.msg = String.format("成功修改%s条数据", num);
        return this;
    }

    public CommonResult deleteSuccess(int num) {
        this.msg = String.format("成功删除%s条数据", num);
        return this;
    }

    public static CommonResult error(String msg) {
        return new CommonResult(ResponseCode.error.code(), msg, null);
    }

    public static CommonResult build(ResponseCode responseCode) {
        return new CommonResult(responseCode.code(), responseCode.desc(), null);
    }

    public CommonResult buildByResponseCode(ResponseCode responseCode) {
        this.code = responseCode.getCode();
        this.msg = responseCode.getDesc();
        return this;
    }

    /**
     * 异常类返回结果处理
     *
     * @param msg
     * @param exception
     * @return
     */
    public static CommonResult error(String msg, String exception) {
        return new CommonResult(ResponseCode.error.code(), msg, exception);
    }

    public static CommonResult error(Integer code, String msg) {
        return new CommonResult(code, msg, null);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

自定义返回内容

@Slf4j
@Component
public class SentinelUrlBlockHandler implements UrlBlockHandler {
    @Override
    public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
        CommonResult<String> errorResponse = null;
        String serverName = "用户服务,";
        // 不同的异常返回不同的提示语
        if (e instanceof FlowException) {
            errorResponse = new CommonResult<>().failed(ResponseCode.serviceFlow.getCode(), serverName + ResponseCode.serviceFlow.getDesc(), null);
        } else if (e instanceof DegradeException) {
            errorResponse = new CommonResult<>().failed(ResponseCode.serviceFuse.getCode(), serverName + ResponseCode.serviceFuse.getDesc(), null);
        } else if (e instanceof ParamFlowException) {
            errorResponse = new CommonResult<>().failed(ResponseCode.serviceHotspot.getCode(), serverName + ResponseCode.serviceHotspot.getDesc(), null);
        } else if (e instanceof SystemBlockException) {
            errorResponse = new CommonResult<>().failed(ResponseCode.serviceSystem.getCode(), serverName + ResponseCode.serviceSystem.getDesc(), null);
        } else if (e instanceof AuthorityException) {
            errorResponse = new CommonResult<>().failed(ResponseCode.serviceRules.getCode(), serverName + ResponseCode.serviceRules.getDesc(), null);
        }

        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        new ObjectMapper().writeValue(response.getWriter(), errorResponse);
    }
}

再次请求,这次就返回自定义的内容了

当然,本文的重点是规则持久化,所以我们可以选择重启服务,看规则是否会消失

我这里选择重启是不会消失的啦,不然也不会发文章哦~

接下来看到我们指定文件存入的规则

如果有伙伴不知道路径在哪里,可如下图找即可~

以上基于本地文件模式持久化规则,到此就结束了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sentinel支持多种持久化方式,包括本地文件、Nacos、Zookeeper等。以下是其中一种本地文件持久化方式的配置示例: 1. 首先,在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-file</artifactId> <version>x.y.z</version> </dependency> ``` 其中,`x.y.z`为Sentinel版本号。 2. 在应用程序的配置文件中,添加以下配置项: ``` spring.cloud.sentinel.datasource.ds1.file.data-type=json spring.cloud.sentinel.datasource.ds1.file.data-source=file:${user.home}/sentinel-rules.json ``` 其中,`ds1`为数据源名称,`data-type`表示持久化文件的格式,这里使用了JSON格式。`data-source`表示持久化文件的路径,这里使用了`${user.home}`表示用户的家目录,`sentinel-rules.json`为规则文件的名称。 3. 在规则文件中添加流控规则,规则文件的默认位置为`${user.home}/sentinel-rules.json`: ``` [ { "resource": "com.example.demo.DemoController:helloSentinel", // 资源名 "limitApp": "default", // 流控针对的调用来源,若为default则不区分调用来源 "grade": 1, // 限流阈值类型,0表示线程数,1表示QPS "count": 10, // 限流阈值 "strategy": 0, // 限流控制行为,0表示直接拒绝,1表示Warm Up,2表示排队等待 "controlBehavior": 0, // 流控效果,0表示快速失败,1表示Warm Up,2表示排队等待 "clusterMode": false // 是否集群限流 } ] ``` 以上就是一个简单的Sentinel流控规则持久化的配置示例。需要注意的是,在实际应用中,可以根据实际需求选择不同的持久化方式。同时,还需要根据实际业务场景设置合理的流控规则,以保证系统的稳定性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值