spring cloud alibaba之sentinel入门

sentinel作为hystrix的替代品现在已慢慢融入我们的日常开发了,虽然阿里官方已经提供了开发文档等资料,但还是有许多地方需要注意,否则也容易出现问题。至于sentinel就不多说了,关于这方面的介绍还是比较多的,大家自行查阅资料即可

1 sentinel控制台的安装

参考资料:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

github上的资料日常开发应该够用了,但站在严谨的角度还是差点意思,例如文档没有写明怎样自定义BlockException、怎样禁止收敛URL的入口context等

2 项目依赖引入和配置

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

修改配置文件加入如下配置:

spring:
  application:
    name: shop-member-sentinel
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080
      filter:
        # sentienl 默认生效,本地调试false
        enabled: false

除filter的配置,其他配置基本也都是参考github,没什么特别的地方,filter的这段配置就是禁止收敛URL的入口context的相关配置

3 禁止收敛URL的入口的代码配置

默认情况下URL的入口context是收敛的,为了让流控模式中的  链路  生效且可正常使用,我们需要写代码禁用URL的入口context收敛,配置代码如下:

package com.debug.config;

import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterContextConfig {

    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

4 自定义规则异常返回

sentinel虽然自带BlockException的返回,但是流控、降级等的异常返回都是一样的,自定义规则异常返回代码如下:

package com.debug.config;

import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class SentinelCustomException implements UrlBlockHandler {


    public void blocked(HttpServletRequest req, HttpServletResponse res, BlockException e) throws IOException {

        res.setContentType("application/json;charset=utf-8");

        ResponseData rd = null;
        //限流异常
        if (e instanceof FlowException) {
            rd = new ResponseData(-1, "程序被限流了");
        } else if (e instanceof DegradeException) {
            //降级异常
            rd = new ResponseData(-2, "程序被降级了");
        } else if (e instanceof AuthorityException) {
            //授权异常
            rd = new ResponseData(-3, "程序访问授权异常");
        }

        res.getWriter().write(JSON.toJSONString(rd));
    }

}



package com.debug.config;

public class ResponseData {

    private Integer code;
    private String message;

    public ResponseData(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public ResponseData() {

    }


    public Integer getCode() {
        return code;
    }

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

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }


}

 

之后新增一个流控规则,看看效果

规则添加之后访问controller出现如下效果

5  @SentinelResource注解的使用

该注解用于标识资源,官方建议使用在service层,要使用在controller上也是可以的,该注解常用的属性值有5个分别是value,fallback,fallbackClass,blockHandler,blockHandlerClass ,先直接上一段代码

    int i=0;
    @SentinelResource(
            value="member-findById",
            fallback = "fallback",
            fallbackClass = SentinelFallBack.class,
            blockHandler = "blockHandler",
            blockHandlerClass = SentinelHandler.class
    )
    public String findById(Integer id) {
        i++;
        if(i%3==0){
            throw new RuntimeException();
        }
        return "ok";
    }

fallback 定义当资源内部发生了Throwable应该进入的方法; blockHandler 定义资源内部发生了BlockException应该进入的方法即sentine定义的异常

package com.debug.sentinel;

import com.alibaba.csp.sentinel.slots.block.BlockException;

public class SentinelHandler {
    public static String blockHandler(Integer id, BlockException e){
        return "出现流控异常";
    }
}
package com.debug.sentinel;


public class SentinelFallBack {

    public static String fallback(Integer id, Throwable e){
        return "出现业务异常";
    }
}

6  sentinel规则持久化

每次我们只要重启微服务,之前配置的规则就没有了,这是因为sentinel的配置默认情况是放在内存中的,但这样对于生产环境不太友好,鉴于这样的原因sentinel也支持把规则持久化到文件、nacos、redis等,这次我查阅资料找了持久话到文件的相关代码

package com.debug.config;

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;

/**
 * 拉模式规则持久化
 *
 * @author itmuch.com
 */
public class FileDataSourceInit implements InitFunc {
    @Override
    public void init() throws Exception {
        // TIPS: 如果你对这个路径不喜欢,可修改为你喜欢的路径
        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 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<>(
            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);
    }
}

光有代码是不行的我们还需要改的地方如下:

resources下创建配置目录META-INF/services,然后添加文件
com.alibaba.csp.sentinel.init.InitFunc

在文件中添加配置类的全路径

com.debug.config.FileDataSourceInit

类的全路径自己的路径是什么就写什么

其他参考资料:https://www.cnblogs.com/spiritmark/p/13009740.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值