spring-cloud-alibaba.2.2.x Sentinel持久化整合nacos,nacos无法获取配置信息bug解决

spring-cloud-alibaba.2.2.x Sentinel持久化整合nacos,nacos无法获取配置信息bug解决

环境版本
jdk1.8.0_201
maven3.6.0
Spring-boot2.2.4.RELEASE
Spring-cloud-alibaba2.2.1.RELEASE
Spring-cloudHoxton.SR2
nacos1.2.1
sentinel-dashboard1.7.1

构建本项目之前,请详细参看如下步骤,如果已经搭建好,略过即可;

项目地址的码云的git地址https://gitee.com/liqi01/badger-spring-cloud-alibaba.git

《spring-cloud-alibaba.2.2.x 服务注册与发现nacos简介以及环境搭建》

《spring-cloud-alibaba2.2.x 远程调用负载均衡ribbon搭建使用》

《spring-cloud-alibaba2.2.x 远程调用负载均衡openfeign搭建使用》

《spring-cloud-alibaba.2.2.x Sentinel分布式系统的流量防卫兵的简介以及环境搭建》

1、特别注意:大坑以及寻求解决办法的思路;

1.1、发现问题

在上述工程,搭建完成后,

1、nacos_1.2.1 启动完成;

2、sentinel-dashboard-1.7.1 启动完成;

3.应用启动完成;

我怎么样都无法获取到nacos中的配置的流控规则?

我应用yaml文件,配置有问题?

流控规则配置有问题,无法获取?

1.2、解决思路

1、翻看源代码

既然在yml文件中配置了sentinel的datasource属性,那么肯定是要实例化这个datasource,找到对应的yml配置的对应的PropertiesConfigurationclass;

com.alibaba.cloud.sentinel.datasource.config.DataSourcePropertiesConfiguration.class

找到对应的datasource属性的get和set方法;

public Map<String, DataSourcePropertiesConfiguration> getDatasource() {
		return datasource;
	}

	public void setDatasource(Map<String, DataSourcePropertiesConfiguration> datasource) {
		this.datasource = datasource;
	}

在通过set方法实例化了对应 datasource后,肯定是有地方调用了getDatasource()方法;

两地地方调用了,

com.alibaba.cloud.sentinel.custom.SentinelDataSourceHandler.class

com.alibaba.cloud.sentinel.endpoint.SentinelEndpoint.class

先看SentinelDataSourceHandler类,在afterSingletonsInstantiated方法中,第一行调用了;这个方法,类似spring的bean的后置处理器,看名字就知道,是在对应实例化时候调用;

大概就是遍历,然后检查一些属性,然后把属性设置到abstractDataSourceProperties,registerBean方法注入这个实例;

@Override
	public void afterSingletonsInstantiated() {
		sentinelProperties.getDatasource()
				.forEach((dataSourceName, dataSourceProperties) -> {
					try {
						List<String> validFields = dataSourceProperties.getValidField();
						if (validFields.size() != 1) {
							log.error("[Sentinel Starter] DataSource " + dataSourceName
									+ " multi datasource active and won't loaded: "
									+ dataSourceProperties.getValidField());
							return;
						}
						AbstractDataSourceProperties abstractDataSourceProperties = dataSourceProperties
								.getValidDataSourceProperties();
						abstractDataSourceProperties.setEnv(env);
						abstractDataSourceProperties.preCheck(dataSourceName);
						registerBean(abstractDataSourceProperties, dataSourceName
								+ "-sentinel-" + validFields.get(0) + "-datasource");
					}
					catch (Exception e) {
						log.error("[Sentinel Starter] DataSource " + dataSourceName
								+ " build error: " + e.getMessage(), e);
					}
				});
	}

debug下,可以看到,已经获取对应的yml的配置,并且把对应的实例,也注入到spring容器中;说明整个配置,容器,都是正常运行,没有什么问题?会不会有什么遗漏的地方?

还是回到yml配置的对应的PropertiesConfigurationclass;

/**
 * Nacos Properties class Using by {@link DataSourcePropertiesConfiguration} and
 * {@link NacosDataSourceFactoryBean}.
 *
 * @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
 */
public class NacosDataSourceProperties extends AbstractDataSourceProperties {

注释上,也提示说明了,可以查看DataSourcePropertiesConfiguration以及NacosDataSourceFactoryBean

配置类,已经看到过了,主要是初始化配置的,直接查看工厂类;在构造方法中,实例化了;

public NacosDataSourceProperties() {
		super(NacosDataSourceFactoryBean.class.getName());
	}

查看NacosDataSourceFactoryBean,实现了spring的FactoryBean接口(不解释),那么直接查看 getObject()方法;

public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {
	@Override
	public NacosDataSource getObject() throws Exception {
		Properties properties = new Properties();
		if (!StringUtils.isEmpty(this.serverAddr)) {
			properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr);
		}
		else {
			properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey);
			properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey);
			properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
		}
		if (!StringUtils.isEmpty(this.namespace)) {
			properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace);
		}
		return new NacosDataSource(properties, groupId, dataId, converter);
	}

设置属性,创建一个NacosDataSource对象,参数,就可以看到了,

properties:配置属性,代码中有具体属性;

groupId:yml中的组信息,默认是DEFAULT_GROUP

dataId:yml中的配置信息;

converter:转换器,上面的文档中,也说明了,默认为json解析器;

代码如下

 public NacosDataSource(final Properties properties, final String groupId, final String dataId,
                           Converter<String, T> parser) {
        super(parser);
        if (StringUtil.isBlank(groupId) || StringUtil.isBlank(dataId)) {
            throw new IllegalArgumentException(String.format("Bad argument: groupId=[%s], dataId=[%s]",
                groupId, dataId));
        }
        AssertUtil.notNull(properties, "Nacos properties must not be null, you could put some keys from PropertyKeyConst");
        this.groupId = groupId;
        this.dataId = dataId;
        this.properties = properties;
        this.configListener = new Listener() {
            @Override
            public Executor getExecutor() {
                return pool;
            }

            @Override
            public void receiveConfigInfo(final String configInfo) {
                RecordLog.info(String.format("[NacosDataSource] New property value received for (properties: %s) (dataId: %s, groupId: %s): %s",
                    properties, dataId, groupId, configInfo));
                T newValue = NacosDataSource.this.parser.convert(configInfo);
                // Update the new value to the property.
                getProperty().updateValue(newValue);
            }
        };
        initNacosListener();
        loadInitialConfig();
    }

主要分三部分吧:

1、初始化成员变量属性;

2、初始化Nacos监听器;

    private void initNacosListener() {
        try {
            this.configService = NacosFactory.createConfigService(this.properties);
            // Add config listener.
            configService.addListener(dataId, groupId, configListener);
        } catch (Exception e) {
            RecordLog.warn("[NacosDataSource] Error occurred when initializing Nacos data source", e);
            e.printStackTrace();
        }
    }

查看初始化监听器的过程,(部分代码过程,比较简单,只贴调用的部分的方法,不贴全部)

2.1、类NacosConfigServiceaddListener方法

/**
 * Config Impl
 *
 * @author Nacos
 */
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosConfigService implements ConfigService {
 		@Override
    public void addListener(String dataId, String group, Listener listener) throws NacosException {
        worker.addTenantListeners(dataId, group, Arrays.asList(listener));
    }  
  

2.2、ClientWorkeraddTenantListeners方法

/**
 * Longpolling
 *
 * @author Nacos
 */
public class ClientWorker {
    public void addTenantListeners(String dataId, String group, List<? extends Listener> listeners) throws NacosException {
      	//初始化group,如果没有,默认设置DEFAULT_GROUP
        group = null2defaultGroup(group);
      //房客?没有看全局代码,暂时不知道有什么作用
        String tenant = agent.getTenant();
      	//获取缓存数据
        CacheData cache = addCacheDataIfAbsent(dataId, group, tenant);
        for (Listener listener : listeners) {
            cache.addListener(listener);
        }
    }
   public CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) throws NacosException {
        CacheData cache = getCache(dataId, group, tenant);
        if (null != cache) {
            return cache;
        }
        String key = GroupKey.getKeyTenant(dataId, group, tenant);
        synchronized (cacheMap) {
            CacheData cacheFromMap = getCache(dataId, group, tenant);
            // multiple listeners on the same dataid+group and race condition,so
            // double check again
            // other listener thread beat me to set to cacheMap
            if (null != cacheFromMap) {
                cache = cacheFromMap;
                // reset so that server not hang this check
                cache.setInitializing(true);
            } else {
                cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group, tenant);
                // fix issue # 1317
                if (enableRemoteSyncConfig) {
                    String[] ct = getServerConfig(dataId, group, tenant, 3000L);
                    cache.setContent(ct[0]);
                }
            }

            Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
            copy.put(key, cache);
            cacheMap.set(copy);
        }
        LOGGER.info("[{}] [subscribe] {}", agent.getName(), key);

        MetricsMonitor.getListenConfigCountMonitor().set(cacheMap.get().size());

        return cache;
    }
}

CacheData addCacheDataIfAbsent(String dataId, String group, String tenant);创建缓存的过程;

大概意思,就是先看缓存中有没有,没有就创建;直接看这段;

 String[] ct = getServerConfig(dataId, group, tenant, 3000L);

getServerConfig方法(部分代码,整体太长了)

 public String[] getServerConfig(String dataId, String group, String tenant, long readTimeout)
        throws NacosException {
        String[] ct = new String[2];
        if (StringUtils.isBlank(group)) {
            group = Constants.DEFAULT_GROUP;
        }

        HttpResult result = null;
        try {
            List<String> params = null;
          	//验证http调用的参数
            if (StringUtils.isBlank(tenant)) {
                params = new ArrayList<String>(Arrays.asList("dataId", dataId, "group", group));
            } else {
                params = new ArrayList<String>(Arrays.asList("dataId", dataId, "group", group, "tenant", tenant));
            }
          	//http调用
            result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
        } catch (IOException e) {
            String message = String.format(
                "[%s] [sub-server] get server config exception, dataId=%s, group=%s, tenant=%s", agent.getName(),
                dataId, group, tenant);
            LOGGER.error(message, e);
            throw new NacosException(NacosException.SERVER_ERROR, e);
        }

主要看这段

 result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);

一个http调用的过程;如果用debug看,可以看到返回的result的code为404;

Constants.CONFIG_CONTROLLER_PATH/v1/cs/configs;有没有很熟悉?

《spring-cloud-alibaba.2.2.x 服务注册与发现nacos简介以及环境搭建》

在nacos搭建的时候,官网给的例子;直接在尝试下;

发布配置

curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

获取配置

curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

这个就尴尬了~原来是nacos的问题,在搭建nacos的时候,nacos的案例,没有生效,可以配置,但是无法获取?

3、加载初始化配置;没有什么好说的,就是加载泛型的类型;

2、发现问题后,解决问题;

1、百度一下,翻看其它的博客,发现并没有什么作用,都是一些,教你怎么搭建的;

2、github官方文档;https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

好像找到了问题所在?jdk版本的问题,我本机的jdk版本;正好是上述的jdk1.8_2.X版本的;

替换jdk版本,再尝试一下;

1、切换jdk版本到1.8.0_181

2、启动nacos

./startup.sh -m standalone

3、在执行nacos的测试案例

curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

成功,非常nice;

1.3、总结

中间也查了博客什么的,确实也没有找到类似的问题,大家在搭建过程中,就没有遇到我这样的问题?就只有我的环境是jdk1.8.2的?

翻看源码,并没有什么用;还是多看官方的文档吧;

中间大量篇幅都是在贴代码,都只是部分的代码,还不是全部的;

看源码什么的,确实也比较消耗时间;

github官方文档;

https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

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

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
Spring Cloud NacosSentinel都支持持久配置文件,可以通过以下步骤进行配置: 1.在Nacos中创建配置文件。可以使用Nacos的Web界面或Nacos的API创建配置文件,例如在Nacos的Web界面中创建名为“sentinel”的配置文件。 2.在Sentinel中添加配置文件。可以通过在Sentinel中添加以下配置来指定Nacos作为配置中心: ``` -Dcsp.sentinel.datasource.type=nacos -Dcsp.sentinel.datasource.nacos.serverAddr=${nacos.serverAddr} -Dcsp.sentinel.datasource.nacos.namespace=${nacos.namespace} -Dcsp.sentinel.datasource.nacos.dataId=${nacos.dataId} -Dcsp.sentinel.datasource.nacos.groupId=${nacos.groupId} ``` 其中,${nacos.serverAddr}、${nacos.namespace}、${nacos.dataId}和${nacos.groupId}是Nacos配置文件的相关信息。 3.在Sentinel中启用持久配置。可以通过在Sentinel Dashboard中配置以下参数来启用持久配置: ``` -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel -Dcsp.sentinel.api.port=8721 -Dcsp.sentinel.dashboard.auth.username=sentinel -Dcsp.sentinel.dashboard.auth.password=sentinel -Dcsp.sentinel.log.use.pid=true -Dcsp.sentinel.datasource.config.file=${user.home}/sentinel/config/properties -Dcsp.sentinel.datasource.config.file.name=sentinel.properties -Dcsp.sentinel.datasource.config.encrypt.key=q9Ec7J6K8sR1T2L4 ``` 其中,${user.home}/sentinel/config/properties是持久配置文件的路径。 4.在Nacos中修改配置文件。可以通过Nacos的Web界面或Nacos的API修改配置文件。例如,在Nacos的Web界面中修改名为“sentinel”的配置文件。 5.在Sentinel中更新配置。可以通过在Sentinel Dashboard中的“配置中心”页面中点击“刷新”按钮来更新配置配置更新后,Sentinel会自动加载新配置。 通过以上步骤,就可以实现Spring Cloud NacosSentinel持久配置文件功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葵花下的獾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值