长沙网站推广系统,微信商城在哪儿打开,2018年靖边建设项目招投标网站,怎么建设自己的一个服务器网站sentinel无法读取nacos配置问题分析 1.spring-cloud-gateway整合sentinel2.问题现象3.原因猜测4.源码分析4. 结语 最近公司需要上线一个集约项目#xff0c;虽然为内网项目#xff0c;但曾经有过内网被攻破#xff0c;导致内部系统被攻击的案例#xff0c;且集约系统同时在… sentinel无法读取nacos配置问题分析 1.spring-cloud-gateway整合sentinel2.问题现象3.原因猜测4.源码分析4. 结语 最近公司需要上线一个集约项目虽然为内网项目但曾经有过内网被攻破导致内部系统被攻击的案例且集约系统同时在线人数较多所以需要对系统整体进行流控。市面上的流控方案有很多不过新系统已经集成了sprin-cloud-alibaba-nacos所以技术选型就选择了阿里的流控系统sentinel。 1.spring-cloud-gateway整合sentinel
springcloud项目整合sentinel需要引入sentinel相关组件 !-- SpringCloud Alibaba Sentinel --dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alibaba-sentinel/artifactId/dependency!-- SpringCloud Alibaba Sentinel Gateway --dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-alibaba-sentinel-gateway/artifactId/dependency因为我们选择将流控规则持久化到nacos中所以还需要引入sentinel的nacos数据库插件依赖 !-- Sentinel Datasource Nacos --dependencygroupIdcom.alibaba.csp/groupIdartifactIdsentinel-datasource-nacos/artifactId/dependency配置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下载sentinel-dashboard的jar包【传送门】执行启动命令java -Dserver.port8088 -Dcsp.sentinel.dashboard.serverlocalhost:8088 -Dcsp.sentinel.app.type1 -Dproject.namesentinel-dashboard -jar sentinel-dashboard-1.8.8.jar还可以指定用户名及密码,通过-Dsentinel.dashboard.auth.username和-Dsentinel.dashboard.auth.password配置,不配置默认用户名密码都是sentinel。启动网关及sentinel控制台查看网关是否已经注册,查看控制台是否已经有服务注册
2.问题现象
上面一通操作之后本地启动了个nacosgateway和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.源码分析 sentinel控制台是从哪里获取的配置文件 sentinel控制台有访问页面既然有页面那么可以从页面查看获取数据入口 sentinel控制台是调用了http://127.0.0.1:8088/gateway/flow/list.json?appmygatewayip127.0.0.1port8720获取了配置的流控规则。到git上把sentinel源码拉下来我们来看看这个接口 GetMapping(/list.json)
AuthAction(AuthService.PrivilegeType.READ_RULE)
public ResultListGatewayFlowRuleEntity queryFlowRules(String app, String ip, Integer port) {// 上面是一些参数校验,不重要,可以不看try {// 这里是获取配置的核心代码// 简单就是网关将自己注册到sentinel时,携带自身的ip和端口(这里可以在启动项配置固定值,如果不配置就是默认本地的ip和网关sentinel端口)// sentinel控制台访问网关集成的sentinel开放的端口,查询持久化在配置中心的配置文件ListGatewayFlowRuleEntity 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 CompletableFutureListGatewayFlowRuleEntity 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 - {ListGatewayFlowRule gatewayFlowRules JSON.parseArray(r, GatewayFlowRule.class);ListGatewayFlowRuleEntity 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 CommandHandlerString {public GetGatewayRuleCommandHandler() {}// 获取配置文件public CommandResponseString handle(CommandRequest request) {// 有效代码就是GatewayRuleManager.getRules()return CommandResponse.ofSuccess(JSON.toJSONString(GatewayRuleManager.getRules()));}
}看一下GatewayRuleManager.getRules() public static SetGatewayFlowRule getRules() {SetGatewayFlowRule rules new HashSet();// 这里是读的内存中的一个map,往下看这个map是GatewayRulePropertyListener在监听器中进行加载和更新的Iterator var1 GATEWAY_RULE_MAP.values().iterator();while(var1.hasNext()) {SetGatewayFlowRule ruleSet (Set)var1.next();rules.addAll(ruleSet);}return rules;
}GatewayRulePropertyListener中的逻辑简单看下 private static final class GatewayRulePropertyListener implements PropertyListenerSetGatewayFlowRule {private GatewayRulePropertyListener() {}public void configUpdate(SetGatewayFlowRule conf) {this.applyGatewayRuleInternal(conf);RecordLog.info([GatewayRuleManager] Gateway flow rules received: {}, new Object[]{GatewayRuleManager.GATEWAY_RULE_MAP});}public void configLoad(SetGatewayFlowRule conf) {this.applyGatewayRuleInternal(conf);RecordLog.info([GatewayRuleManager] Gateway flow rules loaded: {}, new Object[]{GatewayRuleManager.GATEWAY_RULE_MAP});}
}这里是通过监听器调用configLoad方法来初始化加载配置规则但是哪里创建监听器创建的什么监听器从这里已经无法再看出来了。线索中断了。。。。。要放弃吗不小小监听器拿下。既然这个方向已经查不到什么信息了那么我们换一个思路来看看网关这边是在哪里读取nacos配置信息然后顺藤摸瓜应该就能找出到底是哪里读取的文件。 sentinel是如何读取你的配置文件 想要知道哪个类读取的你的配置文件这里使用IDEA的朋友们可以按住control同时单击配置项就能快速定位到引用配置文件。 下面是我们定位到的地方 ConfigurationProperties(// 读取spring.cloud.sentinel下的所有属性配置prefix spring.cloud.sentinel
)
public class SentinelProperties {// 省略其他代码...private MapString, DataSourcePropertiesConfiguration datasource;// 省略其他代码// 我们的配置文件就是映射到MapString, DataSourcePropertiesConfiguration中// map整体结构就是{ds1::{nacos:{....[配置的nacos属性]}}}public void setDatasource(MapString, 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的结构是MapString, DataSourcePropertiesConfiguration datasource。也就是spring会把spring.cloud.sentinel.任意key下的配置全部映射到DataSourcePropertiesConfiguration中。如果你配置的是nacos数据源那么就需要将nacos配置在spring.cloud.sentinel.任意key.nacos下spring会将属性值自动映射到名为nacos的成员变量上这个成员变量的类就是NacosDataSourceProperties。
4. 结语
好了到这里sentinel已经全部拿到nacos的配置信息了后面就是调用nacos rpc接口进行认证及获取配置文件。如果觉得有用就点个赞吧