1 什么是服务发现
- 根据服务名称发现服务的实例过程
- 客户端会在本地缓存服务端的列表
- 拉取列表是有间隔周期的 (导致服务上线 客户端不能第一时间感知到 (可以容忍))
- 其实每次做服务发现 都是从本地的列表来进行的
2 测试服务发现
启动 eureka-server 一台
启动服务 a
启动服务 b
确保服务都上线了
2.1 在 a 服务里面做服务发现
@RestController
public class TestController {
/**
* 注入服务发现组件,我们的 eureka 已经实现了这个接口,所以 IOC 里面有这个对象
*/
@Autowired
private DiscoveryClient discoveryClient;
/**
* 服务发现
*/
@GetMapping("find")
public String find(String serviceId) {
//调用服务发现
List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
instances.forEach(System.out::print);
return instances.toString();
}
}
3 服务发现的源码分析
从 discoveryClient.getInstances(serviceId);方法进去,找到 eureka 的实现
从 getInstancesByVipAddress 方法进去看到真正的服务发现
在 getInstancesByVirtualHostName 方法里面做真正的服务发现
3.1 在 eureka-client 客户端也有 map 集合存放服务列表?
我们发现,当我们还没有做服务发现之前,集合里面已经有值了,说明项目启动的时候就去server 端拉取服务列表并且缓存了起来
3.2 到底何时从 server 拉取服务放进去的呢?
在 eureka 的 DiscoverClient 类的一个构造方法里面,有一个任务调度线程池
查看 initScheduledTasks()这个方法
在 CacheRefreshThread()中
fetchRegistry()方法中判断决定是全量拉取还是增量拉取
getAndStoreFullRegistry()全量拉取
getAndUpdateDelta()增量拉取
3.3 服务发现总结
重要的类:
-
DiscoveryClient 类里面的构造方法执行线程初始化调用(为了后面的拉取服务)
-
CacheRefreshThread 类里面的 run 方法执行服务列表的拉取(方便后期做服务发现)
-
fetchRegistry()方法去判断全量拉取还是增量拉取
全量拉取发生在:当服务列表为 null 的情况 当项目刚启动就全量拉取
增量拉取发生:当服务列表不为 null ,只拉取 eureka-server 的修改的数据(注册新的服务,上线服务)
- eureka 客户端会把服务列表缓存到本地 为了提高性能
- 但是有脏读问题,当你启动一个新的应用的时候 不会被老的应用快速发现。