服务发现
目录
TIP
实例是如何得知其他实例的信息呢?毕竟需要远程调用嘛
两种方式:1.客户端主动获取(定时更新)、2.服务端主动推送(长连接推送变更信息)
客户端主动获取
客户端
1.入口
NacosNamingService.getAllInstances
该方法就是获取所需的服务信息
2.第一次获取
HostReactor.getServiceInfo
1.先是故障转移机制判断是否去本地文件中读取信息,读到则返回
2.再去本地服务列表读取信息(本地缓存),没读到则创建一个空的服务,然后立刻去nacos中读取更新
3.读到了就返回,同时开启定时更新,定时向服务端同步信息 (正常1s,异常最多60s一次)
HostReactor.updateServiceNow
HostReactor.updateService
属性的serverProxy,这里面就是接口调用请求了
3.定时延迟任务
HostReactor.scheduleUpdateIfAbsent
这里全先判断定时任务是否已经在异步任务列表中了,不在才会添加一个UpdateTask任务延迟执行
UpdateTask.run
UpdateTask类就是一个异步执行类,里面会调用updateService方法更新服务信息,同时结束又会开启延迟,延迟的时间跟请求失败的次数有关,最多60s,正常是1s一次
无论是updateService方法、refreshOnly方法,还是刚开始的直接去nacos拉取信息的方法都会调用serverProxy.queryList方法,这个方法就是HTTP请求获取信息:
获取服务信息列表URL:/nacos/v1/ns/instance/list
NamingProxy.queryList
服务端
InstanceController.list()
服务端这边处理请求就比较简单了,除去参数获取以及相关校验就剩服务列表的获取了
InstanceController.doSrvIpxt如下:
这里记住有个PushService
服务端主动推送
既然是主动推送那么就需要两个条件:1.建立长连接2.触发推送的事件
服务端
上面InstanceController.doSrvIpxt中的pushService.addClient就是把客户端UDP、IP等信息封装成PushClient对象存储在PushService类中,方便以后服务变更后推送消息
PushService类实现ApplicationListener接口,监听ServiceChangeEvent(服务变更事件)
ServiceChangeEvent事件处理就在当前类下:
事件触发则是PushService.serviceChanged方法,这个方法之前我们就见过,在服务注册里面,心跳里面也有,服务变更就会调用这个方法,触发事件让服务端主动推送服务变更信息
客户端
客户端是在PushReceiver类里面,这个类是个Runnable会在HostReactor中被实例化
PushReceiver.run()
收到服务端的信息就会交给HostReactor.processServiceJson处理
HostReactor.processServiceJson就会更新本地缓存的信息,上述客户端主动拉取的时候也会调用这个方法更新
HostReactor.processServiceJson
中间一大段省略了哈,最重要的就是那几步:
- 更新本地缓存
- 发布实例变更事件
- 写入磁盘(故障转移机制)
总结
服务的发现有两种方式
客户端主动获取:
- 会先读取缓存,缓存内读取不到则会去服务端获取,同时开启一个定时任务定时更新
- 定时任务1s一次,异常时会延长时间最长60s
- 拉取URL:/nacos/v1/ns/instance/list
服务端主动推送
- 服务端和客户端在启动后会建立一个长连接
- 服务端服务变更后会发布服务变更事件ServiceChangeEvent,会通过长连接将变更后的信息发送给客户端
- 客户端更新的方式是hostReactor.processServiceJson方法,会写入缓存、发布实例变更事件、写入磁盘