eureka的客户端
eurekak客户端同服务端一样,也是通过SPI计算完成的自动配置,它的自动配置类如下
eureka的client实例对象如下
下面是初始化client实例对象的方法
下面是判断客户端是否开启了服务发现和服务注册功能,我们可以通过配置开启或者关闭
创建三个线程池,为后面的执行定时任务做准备
下面是客户端从服务端拿取服务注册信息,fetchRegistry是服务发现的方法,如果没有发现,就会进入if判断通过fetchRegistryFromBackup从备用服务器获取
服务注册
下面就是客户端服务注册的方法
重点是register方法
实现服务注册逻辑的是AbstractJerseyEurekaHttpClient的register方法,可以发现就是发送了一个http的post请求
心跳续约
依然是在客户端实例的初始化方法中,在下面这个方法中初始化了很多定时任务
其中有一个定时任务是用于发送心跳给服务端的,逻辑代码还是在HeartbeatThread中
很简单就是一个run方法,其中renew方法执行发送心跳,后面记录操作时间
可以发现renew方法也只是发送一个http请求
服务发现
同样还是在初始化的时候实现了服务发现
同样也在定时任务中实现了
进入CacheRefreshThread方法
在refreshRegistry方法中同样也调用了这个服务发现方法
fetchRegistry就是服务发现的核心逻辑吗,至于forceFullRegistryFetch这个参数则代表是否强制全量拉取。
- 全量拉取:把eureka服务端所有的注册信息拉取下来;
- 增量拉取:把eureka最近(3分钟之内)更新的注册信息拉取下来。
注意下面首先通过getApplications方法获得本地缓存的服务信息。
其中进入全量拉取的条件有:
- 配置文件中配置的是全量拉取;
- 配置了vip地址,这个vip地址同样是在配置文件中配置,而且这样配置后客户端只会从配置的地址拉取数据;
- 传入的forceFullRegistryFetch为true;
- 本地缓存的服务信息对象为null;
- 本地缓存的服务信息对象的size为0;
- 本地缓存的服务信息对象的版本为-1。
这些条件和上图中的if条件一一对应,其中注意上面vip地址的配置方式如下
这里先看一下增量的方法
首先还是通过一个http请求向服务端获取增量的信息
如果什么都没拉取到还是会执行全量的拉取方法,如果吗,拉取到了就通过updateDelta方法缓存服务信息。
增量获取的信息需要进行处理,简单来说就是首先将增量的数据遍历,通过信息的类别(代码中就是ActionType)判断是需要将服务信息添加到本地缓存还是去除。
至于全量拉取的方法就更加简单了,就只是单纯发送http请求,获取响应中的数据,更新缓存。
至此我们可以回到服务端的服务发现模块,ApplicationsResource存在两个方法负责接收请求,分别处理全量拉取和增量拉取。通过方法中的key对象就可以分别请求的类型。
下面是全量拉取的请求
下面是增量拉取的请求
全量拉取的数据很容易拿到,无非是所有缓存服务信息,但是对于增量拉取的数据则不是这么简单,服务端为了缓存增量拉取的数据维护了一个队列,专门存放增量拉取的数据。
这个列队是在AbstractInstanceRegistry类(这个类的详细说明可以参考对另一篇对服务端的分析)中存储的
而为了维护这个队列在AbstractInstanceRegistry创建时开启了一个定时器,这个定时器会
服务端通过一个队列存储最近的服务操作的信息,通过一个定时器维护这个队列,这个定时器每隔30s会更新队列中的数据,这个队列存储最近发生状态改变的服务实例,如果超过3分钟没有更新状态就会清出这个队列。
下面就是从缓存中取数据代码,其中getApplicationDeltas方法就是增量更新中取队列中数据的方法
服务端还会发送一个hashcode给客户端,这个hashcode就是通过增量的数据计算的
客户端会接收到增量的数据和hashcode,下面会对比这个hashcode和客户端拉取的数据的hashcode,如果不一样代表客户端获取的数据和服务端应该发送的数据不一致,那就是获取失败,就会进入if通过reconcileAndLogDifference再次拉取数据。这个hashcode就是用来校验获取增量数据的。
服务下架
eureka客户端自动下架的方法,spring容器销毁时自动调用,不过这种方式很少见
服务下架方法
当然我们还可以直接通过实例对象直接调用