From c5d2f98427a439f664534543c2e7977d31d3af70 Mon Sep 17 00:00:00 2001 From: ruansheng Date: Mon, 29 Jan 2024 10:23:47 +0800 Subject: [PATCH] Fixed: server pulling old config in Nacos cluster mode (#3600) * Fix nacos config update in Nacos cluster * add capacity limit for nacos config snapshots * add capacity limit for nacos config snapshots * optimized the nacos config snapshot --- .../client/NacosPropertySourceBuilder.java | 12 ++- .../nacos/refresh/NacosContextRefresher.java | 2 + .../refresh/NacosSnapshotConfigManager.java | 76 +++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosSnapshotConfigManager.java diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java index 81e602091..075f0951a 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/client/NacosPropertySourceBuilder.java @@ -22,6 +22,7 @@ import java.util.List; import com.alibaba.cloud.nacos.NacosPropertySourceRepository; import com.alibaba.cloud.nacos.parser.NacosDataParserHandler; +import com.alibaba.cloud.nacos.refresh.NacosSnapshotConfigManager; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.exception.NacosException; import org.slf4j.Logger; @@ -82,7 +83,16 @@ public class NacosPropertySourceBuilder { String fileExtension) { String data = null; try { - data = configService.getConfig(dataId, group, timeout); + String configSnapshot = NacosSnapshotConfigManager.getAndRemoveConfigSnapshot(dataId, group); + if (StringUtils.isEmpty(configSnapshot)) { + log.debug("get config from nacos, dataId: {}, group: {}", dataId, group); + data = configService.getConfig(dataId, group, timeout); + } + else { + log.debug("get config from memory snapshot, dataId: {}, group: {}", + dataId, group); + data = configSnapshot; + } if (StringUtils.isEmpty(data)) { log.warn( "Ignore the empty nacos configuration and get it based on dataId[{}] & group[{}]", diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosContextRefresher.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosContextRefresher.java index b728b1366..90605dd5d 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosContextRefresher.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosContextRefresher.java @@ -129,6 +129,8 @@ public class NacosContextRefresher String configInfo) { refreshCountIncrement(); nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo); + NacosSnapshotConfigManager.putConfigSnapshot(dataId, group, + configInfo); applicationContext.publishEvent( new RefreshEvent(this, null, "Refresh Nacos config")); if (log.isDebugEnabled()) { diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosSnapshotConfigManager.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosSnapshotConfigManager.java new file mode 100644 index 000000000..52645920b --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/refresh/NacosSnapshotConfigManager.java @@ -0,0 +1,76 @@ +/* + * Copyright 2013-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.cloud.nacos.refresh; + +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author: ruansheng + * @date: 2024-01-22 + */ +public final class NacosSnapshotConfigManager { + + private NacosSnapshotConfigManager() { + } + + private static final Logger log = LoggerFactory + .getLogger(NacosSnapshotConfigManager.class); + + private static final Map CONFIG_INFO_SNAPSHOT_MAP = new ConcurrentHashMap<>( + 8); + + private static final int MAX_SNAPSHOT_COUNT = 100; + + private static String formatConfigSnapshotKey(String dataId, String group) { + return dataId + "@" + group; + } + + public static String getAndRemoveConfigSnapshot(String dataId, String group) { + String configInfo = CONFIG_INFO_SNAPSHOT_MAP + .get(formatConfigSnapshotKey(dataId, group)); + removeConfigSnapshot(dataId, group); + return configInfo; + } + + public static void putConfigSnapshot(String dataId, String group, String configInfo) { + try { + // Theoretically, the capacity limit restriction will never be triggered. + // This portion of the code serves as an additional fault tolerance layer. + if (CONFIG_INFO_SNAPSHOT_MAP.size() > MAX_SNAPSHOT_COUNT) { + Iterator> iterator = CONFIG_INFO_SNAPSHOT_MAP + .entrySet().iterator(); + iterator.next(); + iterator.remove(); + } + CONFIG_INFO_SNAPSHOT_MAP.put(formatConfigSnapshotKey(dataId, group), + configInfo); + } + catch (Exception e) { + log.warn("remove nacos config snapshot error", e); + } + } + + public static void removeConfigSnapshot(String dataId, String group) { + CONFIG_INFO_SNAPSHOT_MAP.remove(formatConfigSnapshotKey(dataId, group)); + } + +}