前一篇解析了服务是怎么进行注册的,接下来解析一下服务注册之后服务之间是如何发现彼此的。
相对服务注册而言服务发现就简单很多了。就是Nacos客户端调用Open api或者SDK查询服务列表,服务端接受到请求后根据将查询到服务包装成json格式返回。
既然如此那客户端是啥时候发起服务列表查询?如果客户端查的时差内,刚好有服务实例有dowan掉的,那客户端的请求岂不是有请求到dowan的服务实例去?不是吧?带着这个疑问我们接着分析,揭开一层层疑惑。
根据之前eureka的经验,客户端本身通常会维护一个本地服务地址列表,不会在每次请求时都去请求一次服务端的来拉取最新的服务地址。那么这个本地服务地址列表就有一个时效性问题。
老规矩我们看下spring-cloud-starter-alibaba-nacos-discovery包下的spring.facories文件很容易找到与服务发现相关的配置类。

NacosWatch引起了我的注意为Nacos提供subscribe(String serviceName,EventListener listener)来进行订阅监听。深入一步其实是namingService的subscribe机制,而nacos的NacosNamingService实现了这个接口,我们进入到NacosNamingService的subscribe方法一探究竟,最后发现调用的HostReactor的subscribe方法

注意到客户端有一个HostReactor类,在com.alibaba.nacos.client.naming.core包下。
跟踪进去在scheduleUpdateIfAbsent中发现新增了一个任务。

HostReactor它里面有一个UpdateTask线程,每1s发送一次pull拉取请求,获取服务最新的地址列表。
更新服务的核心逻辑在updateService方法中

在看看processServiceJson方法,本地维护一个Map<String,ServiceInfo> serviceInfoMap存储服务信息,同时调用DiskCache.write(serviceInfo, this.cacheDir)方法把服务信息写入本地缓存文件中;
对于服务端采取的是基于心跳机制push的方式实现的,由于服务端和服务提供者建立心跳机制,一旦服务出现故障,服务端察觉出后,会发送一个push消息给Nacos客户端,也就是我们的消费者。这个push消息是使用DatagramSocket来实现的。
服务消费者收到服务端发来的push消息之后,使用HostReactor中提供的ServiceInfo processServiceJson(String json)方法解析消息,并更新本地服务地址列表。
这里不赘述了,如果不太清晰的话,可以参照下面的图更容易理解服务动态感知原理
