Skip to content

Commit e1970bc

Browse files
committed
feat:Nacos的防抖——获取失败临时使用本地缓存的列表顶一下
1 parent 41d313b commit e1970bc

1 file changed

Lines changed: 65 additions & 15 deletions

File tree

rpc-core/src/main/java/com/xiaoyu/rpc/core/registry/nacos/NacosServiceDiscovery.java

Lines changed: 65 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,33 @@
33
import com.alibaba.nacos.api.exception.NacosException;
44
import com.alibaba.nacos.api.naming.NamingService;
55
import com.alibaba.nacos.api.naming.pojo.Instance;
6-
import lombok.extern.slf4j.Slf4j;
7-
import com.xiaoyu.rpc.core.registry.ServiceDiscovery;
8-
9-
import java.net.InetSocketAddress;
10-
import com.xiaoyu.rpc.core.config.RpcConfig;
6+
import com.alibaba.nacos.api.naming.listener.EventListener;
7+
import com.alibaba.nacos.api.naming.listener.Event;
8+
import com.alibaba.nacos.api.naming.listener.NamingEvent;
119
import com.xiaoyu.rpc.common.extension.ExtensionLoader;
10+
import com.xiaoyu.rpc.core.config.RpcConfig;
1211
import com.xiaoyu.rpc.core.loadbalancer.LoadBalancer;
13-
import java.net.InetSocketAddress;
14-
import java.util.List;
15-
12+
import com.xiaoyu.rpc.core.registry.ServiceDiscovery;
13+
import lombok.extern.slf4j.Slf4j;
1614
import org.slf4j.Logger;
1715
import org.slf4j.LoggerFactory;
1816

17+
import java.net.InetSocketAddress;
18+
import java.util.List;
19+
import java.util.Map;
20+
import java.util.Set;
21+
import java.util.concurrent.ConcurrentHashMap;
22+
import java.util.stream.Collectors;
23+
1924
public class NacosServiceDiscovery implements ServiceDiscovery {
2025
private static final Logger log = LoggerFactory.getLogger(NacosServiceDiscovery.class);
2126

2227
private final NamingService namingService;
2328
private final LoadBalancer loadBalancer;
29+
// 本地缓存,用于容错和防抖
30+
private static final java.util.Map<String, List<Instance>> serviceCache = new java.util.concurrent.ConcurrentHashMap<>();
31+
// 已订阅的服务集合
32+
private static final java.util.Set<String> subscribedServices = java.util.concurrent.ConcurrentHashMap.newKeySet();
2433

2534
public NacosServiceDiscovery() {
2635
this.namingService = NacosUtils.getNacosNamingService();
@@ -31,9 +40,24 @@ public NacosServiceDiscovery() {
3140
@Override
3241
public InetSocketAddress lookupService(String serviceName) {
3342
try {
43+
// 第一次查找时订阅服务变更
44+
if (subscribedServices.add(serviceName)) {
45+
subscribeService(serviceName);
46+
}
47+
48+
// 1. 优先尝试从 Nacos 获取最新实例
3449
List<Instance> instances = namingService.getAllInstances(serviceName);
35-
if (instances.size() == 0) {
36-
log.error("未找到服务: {}", serviceName);
50+
51+
if (instances.isEmpty()) {
52+
log.warn("Nacos 返回实例列表为空,尝试使用本地缓存: {}", serviceName);
53+
instances = serviceCache.get(serviceName);
54+
} else {
55+
// 更新本地缓存
56+
serviceCache.put(serviceName, instances);
57+
}
58+
59+
if (instances == null || instances.isEmpty()) {
60+
log.error("未找到服务且本地无缓存: {}", serviceName);
3761
throw new RuntimeException("未找到服务: " + serviceName);
3862
}
3963

@@ -47,13 +71,39 @@ public InetSocketAddress lookupService(String serviceName) {
4771
log.info("负载均衡选择服务地址: {}", targetAddress);
4872

4973
String[] array = targetAddress.split(":");
50-
String host = array[0];
51-
int port = Integer.parseInt(array[1]);
74+
return new InetSocketAddress(array[0], Integer.parseInt(array[1]));
5275

53-
return new InetSocketAddress(host, port);
5476
} catch (NacosException e) {
55-
log.error("获取服务实例时发生错误:", e);
77+
log.error("获取服务实例时发生网络异常,尝试回滚到本地缓存:", e);
78+
List<Instance> cachedInstances = serviceCache.get(serviceName);
79+
if (cachedInstances != null && !cachedInstances.isEmpty()) {
80+
List<String> addressList = cachedInstances.stream()
81+
.map(instance -> instance.getIp() + ":" + instance.getPort())
82+
.collect(java.util.stream.Collectors.toList());
83+
String targetAddress = loadBalancer.select(addressList);
84+
String[] array = targetAddress.split(":");
85+
return new InetSocketAddress(array[0], Integer.parseInt(array[1]));
86+
}
87+
throw new RuntimeException("服务发现失败且无缓存可用: " + serviceName, e);
5688
}
57-
return null;
89+
}
90+
91+
/**
92+
* 订阅服务变更,实现本地缓存的实时更新
93+
*/
94+
private void subscribeService(String serviceName) throws NacosException {
95+
namingService.subscribe(serviceName, new EventListener() {
96+
@Override
97+
public void onEvent(Event event) {
98+
if (event instanceof NamingEvent) {
99+
NamingEvent namingEvent = (NamingEvent) event;
100+
List<Instance> instances = namingEvent.getInstances();
101+
log.info("监听到服务变更,更新本地缓存: {} -> 实例数 {}", serviceName, instances.size());
102+
if (instances != null && !instances.isEmpty()) {
103+
serviceCache.put(serviceName, instances);
104+
}
105+
}
106+
}
107+
});
58108
}
59109
}

0 commit comments

Comments
 (0)