网关整合sentinel无法读取nacos配置问题分析

sentinel无法读取nacos配置问题分析

  • 1.spring-cloud-gateway整合sentinel
  • 2.问题现象
  • 3.原因猜测
  • 4.源码分析
  • 4. 结语

最近公司需要上线一个集约项目,虽然为内网项目,但曾经有过内网被攻破,导致内部系统被攻击的案例,且集约系统同时在线人数较多,所以需要对系统整体进行流控。市面上的流控方案有很多,不过新系统已经集成了sprin-cloud-alibaba-nacos,所以技术选型就选择了阿里的流控系统sentinel。

1.spring-cloud-gateway整合sentinel

  1. springcloud项目整合sentinel需要引入sentinel相关组件
     <!-- SpringCloud Alibaba Sentinel --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!-- SpringCloud Alibaba Sentinel Gateway --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId></dependency>
    
  2. 因为我们选择将流控规则持久化到nacos中,所以还需要引入sentinel的nacos数据库插件依赖
         <!-- Sentinel Datasource Nacos --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId></dependency>
    
  3. 配置sentinel控制台地址及nacos相关信息
    spring:cloud:nacos:username: your-namepassword: your-passdiscovery:# 服务注册地址server-addr: your-addrnamespace: your-namespaceconfig:# 配置中心地址server-addr: your-addrnamespace: your-namespace# 配置文件格式file-extension: ymlsentinel:# 取消控制台懒加载eager: truetransport:# 控制台地址dashboard: your-dashboard-addr# nacos配置持久化datasource:ds1:nacos:server-addr: ${spring.cloud.nacos.discovery.server-addr}namespace: ${spring.cloud.nacos.discovery.namespace}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}# 限流规则的nacos配置名称dataId: sentinel-gatewaygroupId: DEFAULT_GROUPdata-type: json# 规则类型:网关限流# 这是枚举类,其他类型可以在com.alibaba.cloud.sentinel.datasource.RuleType这个枚举类中查看rule-type: gw-flow
    
  4. 下载sentinel-dashboard的jar包【传送门】;执行启动命令:
    java -Dserver.port=8088 -Dcsp.sentinel.dashboard.server=localhost:8088 -Dcsp.sentinel.app.type=1 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.8.jar
    
    还可以指定用户名及密码,通过-Dsentinel.dashboard.auth.username-Dsentinel.dashboard.auth.password配置,不配置默认用户名密码都是sentinel。
  5. 启动网关及sentinel控制台,查看网关是否已经注册,查看控制台是否已经有服务注册

2.问题现象

  • 上面一通操作之后,本地启动了个nacos,gateway和sentinel控制台看了一下,嗯,没问题,提交,发布测试
  • 测试环境使用k8s部署,部署完网关及sentinel控制台服务后,访问控制台。网关成功注册到nacos及sentinel控制台,再查看流控规则,居然没有读取到nacos中持久化的流控策略

3.原因猜测

  • 问题一出肯定要排查呀,百度了一下有没有人遇到相似的问题,百度的结果很多,但是都不符合我的情况。
  • 猜测问题应该出现在环境问题上。测试环境jdk和本地版本相同,nacos版本相同,sentinel-dashboard版本相同。可能问题出现在配置上。
  • 还记得我们上面怎么配置sentinel datasource的吗
    	  datasource:ds1:nacos:server-addr: ${spring.cloud.nacos.discovery.server-addr}namespace: ${spring.cloud.nacos.discovery.namespace}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}# 限流规则的nacos配置名称dataId: sentinel-gatewaygroupId: DEFAULT_GROUPdata-type: json# 规则类型:网关限流# 这是枚举类,其他类型可以在com.alibaba.cloud.sentinel.datasource.RuleType这个枚举类中查看rule-type: gw-flow
    
    因为我们是部署在k8s中,nacos的访问地址密码等都配置在环境变量中,相当于bootstrap.yml的配置的配置其实一直是本地的配置,而 ${spring.cloud.nacos.discovery.server-addr}这种配置方式是直接读取bootstrap.yml中的nacos地址,其他的属性也是如此,相当于读取的全部都是本地环境的nacos配置,导致sentinel读取配置文件失败。
  • 解决方法:springboot支持直接读取系统环境变量,配置方法也是${系统变量名},并开启了sentinel日志配置,配置如下:
        sentinel:# 取消控制台懒加载eager: truetransport:# 控制台地址dashboard: 127.0.0.1:8088# nacos配置持久化ds1:datasource:nacos:server-addr: ${NacosServerAddr}namespace: ${ConfigNamespace}username: ${username}password: ${password}dataId: sentinel-iwos-gatewaygroupId: DEFAULT_GROUPdata-type: jsonrule-type: gw-flowlog:dir: /usr/local/logs/iwos-gateway
    
    再次发布版本启动网关,查看sentinel控制台发现已经能够从nacos中读取持久化流控策略。问题到这里已经解决了,如果你和我一样好奇sentinel是如何从nacos配置文件中读取配置文件的话,那就继续往下看吧

4.源码分析

  1. sentinel控制台是从哪里获取的配置文件

    • sentinel控制台有访问页面,既然有页面那么可以从页面查看获取数据入口
      在这里插入图片描述

    • sentinel控制台是调用了http://127.0.0.1:8088/gateway/flow/list.json?app=mygateway&ip=127.0.0.1&port=8720获取了配置的流控规则。到git上把sentinel源码拉下来,我们来看看这个接口:

    @GetMapping("/list.json")
    @AuthAction(AuthService.PrivilegeType.READ_RULE)
    public Result<List<GatewayFlowRuleEntity>> queryFlowRules(String app, String ip, Integer port) {// 上面是一些参数校验,不重要,可以不看try {// 这里是获取配置的核心代码// 简单就是网关将自己注册到sentinel时,携带自身的ip和端口(这里可以在启动项配置固定值,如果不配置就是默认本地的ip和网关sentinel端口)// sentinel控制台访问网关集成的sentinel开放的端口,查询持久化在配置中心的配置文件List<GatewayFlowRuleEntity> rules = sentinelApiClient.fetchGatewayFlowRules(app, ip, port).get();repository.saveAll(rules);return Result.ofSuccess(rules);} catch (Throwable throwable) {logger.error("query gateway flow rules error:", throwable);return Result.ofThrowable(-1, throwable);}
    }
    

    所以其实配置文件不是dashboard控制台去读取的,而是从网关的sentinel开放的restapi中拉取。

        public CompletableFuture<List<GatewayFlowRuleEntity>> fetchGatewayFlowRules(String app, String ip, int port) {if (StringUtil.isBlank(ip) || port <= 0) {return AsyncUtils.newFailedFuture(new IllegalArgumentException("Invalid parameter"));}try {// FETCH_GATEWAY_FLOW_RULE_PATH: gateway/getRules// 这里就是通过rest请求获取配置文件return executeCommand(ip, port, FETCH_GATEWAY_FLOW_RULE_PATH, false).thenApply(r -> {List<GatewayFlowRule> gatewayFlowRules = JSON.parseArray(r, GatewayFlowRule.class);List<GatewayFlowRuleEntity> entities = gatewayFlowRules.stream().map(rule -> GatewayFlowRuleEntity.fromGatewayFlowRule(app, ip, port, rule)).collect(Collectors.toList());return entities;});} catch (Exception ex) {logger.warn("Error when fetching gateway flow rules", ex);return AsyncUtils.newFailedFuture(ex);}}
    

    控制台是请求网关gateway/getRules这个路径来获取配置文件的,完整的url为: http://ip:port/gateway/getRules
    来看看网关sentinel这个api是怎么工作的。

    @CommandMapping(
    name = "gateway/getRules",
    desc = "Fetch all gateway rules"
    )
    public class GetGatewayRuleCommandHandler implements CommandHandler<String> {public GetGatewayRuleCommandHandler() {}// 获取配置文件public CommandResponse<String> handle(CommandRequest request) {// 有效代码就是GatewayRuleManager.getRules()return CommandResponse.ofSuccess(JSON.toJSONString(GatewayRuleManager.getRules()));}
    }
    

    看一下GatewayRuleManager.getRules()

    public static Set<GatewayFlowRule> getRules() {Set<GatewayFlowRule> rules = new HashSet();// 这里是读的内存中的一个map,往下看这个map是GatewayRulePropertyListener在监听器中进行加载和更新的Iterator var1 = GATEWAY_RULE_MAP.values().iterator();while(var1.hasNext()) {Set<GatewayFlowRule> ruleSet = (Set)var1.next();rules.addAll(ruleSet);}return rules;
    }
    

    GatewayRulePropertyListener中的逻辑简单看下

    private static final class GatewayRulePropertyListener implements PropertyListener<Set<GatewayFlowRule>> {private GatewayRulePropertyListener() {}public void configUpdate(Set<GatewayFlowRule> conf) {this.applyGatewayRuleInternal(conf);RecordLog.info("[GatewayRuleManager] Gateway flow rules received: {}", new Object[]{GatewayRuleManager.GATEWAY_RULE_MAP});}public void configLoad(Set<GatewayFlowRule> conf) {this.applyGatewayRuleInternal(conf);RecordLog.info("[GatewayRuleManager] Gateway flow rules loaded: {}", new Object[]{GatewayRuleManager.GATEWAY_RULE_MAP});}
    }
    

    这里是通过监听器调用configLoad方法来初始化加载配置规则,但是哪里创建监听器,创建的什么监听器,从这里已经无法再看出来了。线索中断了。。。。。要放弃吗?不!小小监听器,拿下。既然这个方向已经查不到什么信息了,那么我们换一个思路,来看看网关这边是在哪里读取nacos配置信息,然后顺藤摸瓜应该就能找出到底是哪里读取的文件。

  2. sentinel是如何读取你的配置文件
    想要知道哪个类读取的你的配置文件,这里,使用IDEA的朋友们可以按住control,同时单击配置项,就能快速定位到引用配置文件。
    下面是我们定位到的地方:

    @ConfigurationProperties(// 读取spring.cloud.sentinel下的所有属性配置prefix = "spring.cloud.sentinel"
    )
    public class SentinelProperties {// 省略其他代码...private Map<String, DataSourcePropertiesConfiguration> datasource;// 省略其他代码// 我们的配置文件就是映射到Map<String, DataSourcePropertiesConfiguration>中// map整体结构就是{"ds1:":{"nacos":{....[配置的nacos属性]}}}public void setDatasource(Map<String, DataSourcePropertiesConfiguration> datasource) {this.datasource = datasource;}
    }
    

    如果不是用IDEA开发的要怎么看呢,其实也有个通用的方法,
    去看resources中META-INFO目录下spring自动装配的类。sentinel入口jar包是spring-cloud-starter-alibaba-sentinel-2021.0.6.0.jar。META-INFO下有一个spring.factories文件,spring会在启动的时候加载这个文件中的工厂类。看看这个文件里有哪些:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.alibaba.cloud.sentinel.SentinelWebAutoConfiguration,\
    com.alibaba.cloud.sentinel.SentinelWebFluxAutoConfiguration,\
    com.alibaba.cloud.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
    com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration,\
    com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration
    

    加载用户配置的是SentinelAutoConfiguration类。

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
    @EnableConfigurationProperties(SentinelProperties.class)
    public class SentinelAutoConfiguration {@Value("${project.name:${spring.application.name:}}")private String projectName;@Autowiredprivate SentinelProperties properties;// 其他代码省略....
    }
    

    可以看到这里在创建bean的时候注入了SentinelProperties,也就是刚才我们通过IDEA定位到的配置类。

    两种方法都了解之后我们继续看SentinelProperties中的DataSourcePropertiesConfiguration

    public class DataSourcePropertiesConfiguration {// 省略其他数据源的代码配置...// 刚才的setDatasource就是拿到map中的value找到对应的属性类,也就是{"nacos":{...[配置的nacos属性]}}// 从这里可以看出datasource的key是无所谓写什么值得,也就是配置类中的ds1.nacos可以替换成任意key.nacos// 测试了一下改成datasource.nacos也完全没有问题private NacosDataSourceProperties nacos;
    }
    

    nacos配置类

    public class NacosDataSourceProperties extends AbstractDataSourceProperties {// 这些都是sentinel可以配置的nacos配置项private String serverAddr;private String contextPath;private String username;private String password;@NotEmptyprivate String groupId = "DEFAULT_GROUP";@NotEmptyprivate String dataId;private String endpoint;private String namespace;private String accessKey;private String secretKey;public NacosDataSourceProperties() {super(NacosDataSourceFactoryBean.class.getName());}// 预先检查,如果地址为空就设置一个默认的nacos地址@Overridepublic void preCheck(String dataSourceName) {if (StringUtils.isEmpty(serverAddr)) {serverAddr = this.getEnv().getProperty("spring.cloud.sentinel.datasource.nacos.server-addr","127.0.0.1:8848");}}
    }
    

    nacos配置类就是我们常规的配置,还记得sentinel是在哪个key下找到nacos的配置吗,可以回去看看sentinelProperties。它从spring.cloud.sentinel下读取一个map作为数据源。这个map的结构是Map<String, DataSourcePropertiesConfiguration> datasource。也就是spring会把spring.cloud.sentinel.任意key下的配置全部映射到DataSourcePropertiesConfiguration中。如果你配置的是nacos数据源,那么就需要将nacos配置在spring.cloud.sentinel.任意key.nacos下,spring会将属性值自动映射到名为nacos的成员变量上,这个成员变量的类就是NacosDataSourceProperties

4. 结语

好了,到这里sentinel已经全部拿到nacos的配置信息了,后面就是调用nacos rpc接口进行认证及获取配置文件。如果觉得有用就点个赞吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/481592.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用ECharts创建带百分比标注的环形图

在数据可视化领域&#xff0c;环形图是一种非常有效的图表类型&#xff0c;它能够清晰地展示各部分与整体的关系。今天&#xff0c;我们将通过ECharts来创建一个带百分比标注的环形图&#xff0c;并详细解释如何实现这一效果。 1. 数据准备 首先&#xff0c;我们定义了一些基础…

AIGC训练效率与模型优化的深入探讨

文章目录 1.AIGC概述2.AIGC模型训练效率的重要性3.模型优化的概念与目标4.模型优化策略4.1 学习率调节4.2 模型架构选择4.3 数据预处理与增强4.4 正则化技术4.5 量化与剪枝 5.代码示例6.结论 人工智能领域的发展&#xff0c;人工智能生成内容&#xff08; AIGC&#xff09;越来…

keil 5. Flash Timeout. Reset the Target and try it again.

使用官方STM32 ST-LINK Utility 烧写软件 KEIL 5, 设置DFP 包支持FLASH烧写算法 Keil 5, Flash Timeout. Reset the Target and try it again.-CSDN博客

Vim操作

1. Vim的模式 2.正常模式->编辑模式 在上⽅插⼊⼀⾏&#xff1a; O在下⽅插⼊⼀⾏&#xff1a; o (open)在当前光标前插⼊&#xff1a; i在⾏⾸插⼊&#xff1a; I在当前光标后插⼊&#xff1a; a在⾏尾插⼊&#xff1a; A 3.常见命令行 1、拷贝当前行 yy ,拷贝当前行向下…

SAP Native SQL 的简单说明

Open SQL访问数据字典中声明的数据库表&#xff0c;不区分数据库类型&#xff0c;执行时会自动转换为对应的语句&#xff0c;且可以使用本地缓存。Native SQL使用特定于数据库的SQL语句,但是可以访问比Open SQL 更多的表&#xff0c;更多的操作&#xff0c;缺点也很明显&#x…

【娱乐项目】竖式算术器

Demo介绍 一个加减法随机数生成器&#xff0c;它能够生成随机的加减法题目&#xff0c;并且支持用户输入答案。系统会根据用户输入的答案判断是否正确&#xff0c;统计正确和错误的次数&#xff0c;并显示历史记录和错题记录。该工具适合用于数学练习&#xff0c;尤其适合练习基…

【深度学习】各种卷积—卷积、反卷积、空洞卷积、可分离卷积、分组卷积

在全连接神经网络中&#xff0c;每个神经元都和上一层的所有神经元彼此连接&#xff0c;这会导致网络的参数量非常大&#xff0c;难以实现复杂数据的处理。为了改善这种情况&#xff0c;卷积神经网络应运而生。 一、卷积 在信号处理中&#xff0c;卷积被定义为一个函数经过翻转…

智能化图书馆导航系统方案之系统架构与核心功能设计

hello~这里是维小帮&#xff0c;点击文章最下方获取图书馆导航系统解决方案&#xff01;如有项目需求和技术交流欢迎大家私聊我们~撒花&#xff01; 针对传统图书馆在图书查找困难、座位紧张、空间导航不便方面的问题&#xff0c;本文深入剖析了基于高精度定位、3D建模、图书搜…

K8s内存溢出问题剖析:排查与解决方案

文章目录 一、背景二、排查方案&#xff1a;1. 可能是数据量超出了限制的大小&#xff0c;检查数据目录大小2. 查看是否是内存溢出2.1 排查数据量&#xff08;查看数据目录大小是否超过limit限制&#xff09;2.2 查看pod详情发现问题 三、解决过程 一、背景 做redis压测过程中…

ospf协议(动态路由协议)

ospf基本概念 定义 OSPF 是典型的链路状态路由协议&#xff0c;是目前业内使用非常广泛的 IGP 协议之一。 目前针对 IPv4 协议使用的是 OSPF Version 2 &#xff08; RFC2328 &#xff09;&#xff1b;针对 IPv6 协议使用 OSPF Version 3 &#xff08; RFC2740 &#xff09;。…

基于云模型和遗传算法的建设工程风险决策多目标优化研究

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于云模型和遗传算法的建设工程风险决策多目标优化研究 基于云模型和遗传算法的建设工程风险决策多目标优化研究涉及在建设工程领域中运用云模型和遗传算法来优化风险决策的多个目标。云模型是一种将模糊理论与概率…

【C语言】连接陷阱探秘(5):头文件

目录 一、头文件的作用 1.1. 声明共享 1.2. 模块化 1.3. 实践中的注意事项 二、常见的头文件陷阱 2.1 重复包含(Include Guards) 2.1.1. Include Guard 工作原理 2.1.2. Pragma Once(某些编译器支持) 2.2 循环依赖(Circular Dependencies) 2.2.1. 前向声明 2.…

C++:异常

---什么是异常&#xff1f; 异常是面向对象语法处理错误的一种方式。 ---C语言传统的处理错误的方式有哪些呢&#xff1f; 1.返回错误码&#xff0c;有些API接口都是把错误码放到errno中。 2.终止程序&#xff0c;比如发生越界等严重问题时&#xff0c;我们也可以主动调用exit…

2023年MathorCup高校数学建模挑战赛—大数据竞赛B题电商零售商家需求预测及库存优化问题求解全过程文档及程序

2023年MathorCup高校数学建模挑战赛—大数据竞赛 B题 电商零售商家需求预测及库存优化问题 原题再现&#xff1a; 电商平台存在着上千个商家&#xff0c;他们会将商品货物放在电商配套的仓库&#xff0c;电商平台会对这些货物进行统一管理。通过科学的管理手段和智能决策&…

前端node.js

一.什么是node.js 官网解释:Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。 二.初步使用node.js 需要区分开的是node.js和javascript互通的只有console和定时器两个API. 三.Buffer Buffer 是一个类似于数组的 对象&#xff0c;用于表示固定长度的字节序列。Buffer…

偏差-方差权衡(Bias–Variance Tradeoff):理解监督学习中的核心问题

偏差-方差权衡&#xff08;Bias–Variance Tradeoff&#xff09;&#xff1a;理解监督学习中的核心问题 在机器学习中&#xff0c;我们希望构建一个能够在训练数据上表现良好&#xff0c;同时对未见数据也具有强大泛化能力的模型。然而&#xff0c;模型的误差&#xff08;尤其…

go-zero使用自定义模板实现统一格式的 body 响应

前提 go环境的配置、goctl的安装、go-zero的基本使用默认都会 需求 go-zero框架中&#xff0c;默认使用goctl命令生成的代码并没有统一响应格式&#xff0c;现在使用自定义模板实现统一响应格式&#xff1a; {"code": 0,"msg": "OK","d…

Matlab热力图巅峰之作

准备‘data.xlsx’ 的热力图文件&#xff1a; main&#xff1a; clc; clear; close all; % 相关性气泡热图%% 数据准备 % 读取Excel文件数据 data readmatrix(data.xlsx); % 读取Excel文件中的数据%% 颜色定义 map colormap("cool"); map map([2:6,9:13],1:3)…

时序论文28|CycleNet:通过对周期模式进行建模增强时间序列预测

论文标题&#xff1a;CycleNet: Enhancing Time Series Forecasting through Modeling Periodic Patterns 论文链接&#xff1a;https://arxiv.org/abs/2409.18479v1 代码链接&#xff1a;https://github.com/ACAT-SCUT/CycleNet 前言 这是今年NIPS的一篇时序论文&#xff…

自动化运维(k8s)之微服务信息自动抓取:namespaceName、deploymentName等全解析

前言&#xff1a;公司云原生k8s二开工程师发了一串通用性命令用来查询以下数值&#xff0c;我想着能不能将这命令写成一个自动化脚本。 起初设计的 版本一&#xff1a;开头加一条环境变量&#xff0c;执行脚本后&#xff0c;提示输入&#xff1a;需要查询的命名空间&#xff0c…