33import com .alibaba .nacos .api .exception .NacosException ;
44import com .alibaba .nacos .api .naming .NamingService ;
55import 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 ;
119import com .xiaoyu .rpc .common .extension .ExtensionLoader ;
10+ import com .xiaoyu .rpc .core .config .RpcConfig ;
1211import 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 ;
1614import org .slf4j .Logger ;
1715import 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+
1924public 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