sentinel + nacos 超详细使用步骤

1、前言

sentinel的简介和使用的详细文档请参考 https://sentinelguard.io/zh-cn/docs/introduction.html
nacos的搭建和使用介绍请参考 https://nacos.io/zh-cn/docs/quick-start.html

首先我们要明白在使用sentinel的时候有几种模式,具体有哪几种可以参考详细文档,这里我们只说明最适用于生产上的模式。
sentinel-dashboard(sentinel控制台)用于页面化监控服务,页面配置限流、熔断、系统保护、热点、来源访问控制等。
nacos用于持久化和动态配置sentinel的规则。
这里我们直接上操作步骤

2、启动sentinel-dashboard

  1. 首先在sentinel-dashboard这个连接中下载对应的jar包。
  2. 下载完成后, 使用下面命令进行启动
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456 -jar sentinel-dashboard-1.8.5.jar

启动参数解释:
-Dserver.port=8080 										// 指定启动端口
-Dcsp.sentinel.dashboard.server=localhost:8080    		// 指定服务
-Dproject.name=sentinel-dashboard						// 指定sentinel控制台服务的名字
-Dsentinel.dashboard.auth.username=sentinel				// 指定sentinel登录名
-Dsentinel.dashboard.auth.password=123456				// 指定sentinel登录密码

  1. 看到一下日志表示启动成功(这里暂时没有遇到过启动失败的情况,又遇到失败的朋友可以评论沟通一下)
    sentinel + nacos 超详细使用步骤_第1张图片
  2. 登录页面
    sentinel + nacos 超详细使用步骤_第2张图片
  3. sentinel首页,这里因为还没有在sentinel-dashboard接入,所以还看不到我们的项目,这里我们调用一下项目的接口,便可以在控制台中看到我们的项目
    sentinel + nacos 超详细使用步骤_第3张图片

3、项目配置

1、maven配置

		
		<dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-coreartifactId>
            <version>1.8.5version>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-transport-simple-httpartifactId>
            <version>1.8.5version>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-annotation-aspectjartifactId>
            <version>1.8.5version>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
            <version>2.1.0.RELEASEversion>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cspgroupId>
            <artifactId>sentinel-datasource-nacosartifactId>
            <version>1.8.5version>
        dependency>

2、application.xml配置

这里只配置流控、熔断、授权的配置,其他配置是相同的。
在生产上部署的时候这里需要配置一下心跳地址,注意使用client-ip而不是clientIp

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
        client-ip: [ip]  # 在生产上部署的时候这里需要配置一下心跳地址,注意使用client-ip而不是clientIp
      datasource:
        flow:
          nacos:
            server-addr: localhost:8848  # nacos连接地址
            namespace: d95f824e-9eb5-4181-be30-9fc4c5edf1f2
            group-id: DEFAULT_GROUP  # nacos连接的分组
            rule-type: flow  # 流控规则  rule-type 配置表示该数据源中的规则属于哪种类型的规则(flow,degrade,authority,system, param-flow, gw-flow, gw-api-group)
            data-id: sentinel-flow  # 读取配置文件的 data-id
            data-type: json #  读取培训文件类型为json
        degrade:
          nacos:
            server-addr: localhost:8848
            namespace: d95f824e-9eb5-4181-be30-9fc4c5edf1f2
            group-id: DEFAULT_GROUP
            rule-type: degrade
            data-id: sentinel-degrade
            data-type: json
        authority:
          nacos:
            server-addr: localhost:8848
            namespace: d95f824e-9eb5-4181-be30-9fc4c5edf1f2
            group-id: DEFAULT_GROUP
            rule-type: authority
            data-id: sentinel-authority
            data-type: json

3、接口配置

3.1、注解使用

value和sentinel中配置的接口地址值要一致
blockHandler是指定的通用流控异常返回类,如果写在该注解注用的方法的同一个类中,那么blockHandlerClass便不用指定,如果有通用的异常处理类,blockHandlerClass需要指定类

@SentinelResource(value = "xxx", blockHandler = "generalBlockHandler", blockHandlerClass = {BlockHandlerUtils.class})
public class BlockHandlerUtils {

    public static RespResult generalBlockHandler(JSONObject jsonObject, BlockException e) {
        e.printStackTrace();
        String msg = "未知异常";
        int status = 429;

        if (e instanceof FlowException) {
            msg = "请求被限流了";
        } else if (e instanceof ParamFlowException) {
            msg = "请求被热点参数限流";
        } else if (e instanceof DegradeException) {
            msg = "请求被降级了";
        } else if (e instanceof AuthorityException) {
            msg = "没有权限访问";
            status = 401;
        }
        return new RespResult(status, msg);
    }
}

3.2 自定义规则

public static void main(String[] args) {
    // 配置规则.
    initFlowRules();

    while (true) {
        // 1.5.0 版本开始可以直接利用 try-with-resources 特性
        try (Entry entry = SphU.entry("HelloWorld")) {
            // 被保护的逻辑
            System.out.println("hello world");
	} catch (BlockException ex) {
            // 处理被流控的逻辑
	    System.out.println("blocked!");
	}
    }
}

private static void initFlowRules(){
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule();
   	// 这里
    rule.setResource("HelloWorld");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // Set limit QPS to 20.
    rule.setCount(20);
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

具体的规则和详细的配置就不在这里赘述了,大家可以自行去sentinel中文官网去查询。

4、Nacos适配指定数据库和启动

Nacos本身仅支持Mysql数据库,但实际开发中,我们可能要用到其他的数据库进行存储,大家可以根据https://blog.csdn.net/weixin_43148701/article/details/126015374
这片文章进行修改数据库,但是其中可能会遇到不少问题,在这里说明一下:
1、idea要下载一下插件Protobuf,没有这个插件,编译会报错
2、nacos源码中的pom-all.xml中需要修改下面两个依赖的版本号,可根据nacos版本自行进行升级,我这里用的是nacos-2.1.2,源码中本身所用的版本,在我本地编译不过,网上也找了本多解决版本,大多不能生效,进行了版本升级后成功编译通过。
sentinel + nacos 超详细使用步骤_第4张图片
3、打包的时候可能会出现错误,但只要整体打包成功,便没有问题。
4、Nacos启动的时候使用./startup.sh -m standalone,即可启动单机版,默认是集群

5、Nacos发布sentinel

1、根据不同的业务流程可以在代码中进行动态发布和删除相关规则,这里我以授权规则为例,进行介绍

@Configuration
@Slf4j
public class NacosConfig {

    @Value("${spring.cloud.sentinel.datasource.authority.nacos.server-addr}")
    private String serverAddr;
    @Value("${spring.cloud.sentinel.datasource.authority.nacos.namespace}")
    private String namespace;

    @Bean
    @Primary
    public ConfigService configService() {
        Properties properties = new Properties();
        properties.put("serverAddr", serverAddr);
        properties.put("namespace", namespace);
        try {
            return NacosFactory.createConfigService(properties);
        } catch (NacosException e) {
            log.error(e.toString(), e);
        }
        return null;
    }
}
@Component
@Slf4j
public class NacosListener {

    @Resource
    ConfigService configService;

    @Value("${spring.cloud.sentinel.datasource.authority.nacos.group-id}")
    private String sentinelAuthorityGroupId;

    @Value("${spring.cloud.sentinel.datasource.authority.nacos.data-id}")
    private String sentinelAuthorityDataId;

    /**
     * 向nacos发布初始化内容
     *
     * @param jsonArray 发布的数据
     * @throws Exception 抛出的异常
     */
    public void insertAuthConfig(JSONArray jsonArray) throws Exception {
        // 先查询一下nacos上是否已有数据
        String config = configService.getConfig(sentinelAuthorityDataId, sentinelAuthorityGroupId, 5000);
        JSONArray parseArray = JSONArray.parseArray(config);
        if (parseArray.size() > 0) {
            updateAuthConfig(jsonArray);
        } else {
            // 如果nacos上没有授权规则的数据则进行新增
            //发布内容
            boolean b = configService.publishConfig(sentinelAuthorityDataId, sentinelAuthorityGroupId, jsonArray.toJSONString());
            if (b) {
                log.info("Nacos发布成功!");
            } else {
                log.error("Nacos发布失败!");
            }
        }
    }

    /**
     * 修改nacos的配置
     *
     * @param array 发布的数据
     */
    public void updateAuthConfig(JSONArray array) throws NacosException {
        String config = configService.getConfig(sentinelAuthorityDataId, sentinelAuthorityGroupId, 5000);
        JSONArray jsonArray = JSONArray.parseArray(config);
        boolean flag = false;
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject json = jsonArray.getJSONObject(i);
            for (int j = 0; j < array.size(); j++) {
                JSONObject jsonObject = array.getJSONObject(j);
                if (json.getString("resource").equalsIgnoreCase(jsonObject.getString("resource"))) {
                    // 查看一下nacos上是否有关于传入访问地址的白名单如果有,那么就对将传入的IP加到原有的
                    String limitApp = json.getString("limitApp");
                    String ip = jsonObject.getString("limitApp");
                    String[] split = limitApp.split(",");
                    boolean f = false;
                    for (String s : split) {
                        if (s.equalsIgnoreCase(ip)) {
                            f = true;
                            break;
                        }
                    }
                    if (!f) {
                        limitApp += "," + ip;
                    } else {
                        log.info("Nacos上已有需要发布的数据!");
                        return;
                    }
                    json.put("limitApp", limitApp);
                    flag = true;
                }
            }
        }
        boolean b;
        if (flag) {
            // nacos上有需要添加给名单的资源,将ip进行添加
            b = configService.publishConfig(sentinelAuthorityDataId, sentinelAuthorityGroupId, jsonArray.toString());
        } else {
            // nacos没有需要添加的资源,将资源进行添加
            jsonArray.addAll(array);
            b = configService.publishConfig(sentinelAuthorityDataId, sentinelAuthorityGroupId, jsonArray.toString());
        }
        if (b) {
            log.info("Nacos发布成功!");
        } else {
            log.error("Nacos发布失败!");
        }
    }
}

到此基本就差不多啦,有问题的道友们,欢迎评论区留言!

你可能感兴趣的:(sentinel,java,微服务)