服务下线(主动下线)client发起的
要下线的时候会调用shutdown方法,然后shutdown方法调用了unregister方法
调用AbstractJerseyEurekaHttpClient 的cancel方法:
发送http请求告诉eureka-server自己下线。
之后这个请求就会被server服务端收到,然后服务端调用cancel方法进行服务取消注册
这里最后又调用了internalCancel这个方法后根据id去gmap中删除对应的实例
服务发现
服务发现也就是一个服务去发现另一个服务,或者客户端去发现另一个服务的过程
可以通过DicoveryClient的getInstances方法去得到当前serviceId对应的服务的信息。
getInstancesByVipAddress这个方法用于进行服务发现。
首先判断本地是否有这个服务,如果本地有,那么就从本地直接拿。
如果没有,那么就从远程拿。
最后applications.getInstancesByVirtualHostName才是真正的获取服务列表
这里通过get方法真正的拿到了服务实例的集合
夸张的地方就在这里,因为明明我们还没有调用完毕getInstances获取实例的方法,但是这个map集合中就已经有了所有实例的数据了,这说明一定是在我们还没有调用getInstances试图去获取注册的实例之前,eureka就已经获取到了所有的实例了,并且把他们缓存在自己的信息中了。
也就是在我们还没有做服务发现之前,集合里面已经有值了,说明项目启动的时候就已经去server端里面拉取了所有服务并且进行了缓存。(这里的eureka是我是用客户端发送的,为下图comsumer,eureka-server表示的是注册中心,也就是说consumer这个客户端在我还没有进行服务发现的时候他就已经把server中的所有的服务都已经拉取到本地进行缓存了)
这个构造函数中有一个任务调度线程池
在 CacheRefreshThread()中
fetchRegistry()方法中判断决定是全量拉取还是增量拉取
这个方法就是用来拉取服务的
如果有新增服务,那么就进行增量拉取
如果服务列表为null,那么就直接进行全量拉取
第一个箭头指向的是向eureka-server拉取服务
第二个箭头是指把服务放入到本地服务列表中
下面是增量拉取
12表示先拉取服务列表,如果服务列表为null,那么直接进行一次全量拉取
不为空则进行增量拉取,然后进行一次一致性hash算法,判断此时的服务列表是否与eureka-server中的服务是一样的,如果一样,那么成功,否则在进行一次拉取。
DiscoveryClient 类里面的构造方法执行线程初始化调用
CacheRefreshThread 类里面的 run 方法执行服务列表的拉取(方便后期做服务发现)
fetchRegistry()方法去判断全量拉取还是增量拉取
全量拉取发生在:当服务列表为 null 的情况 当项目刚启动就全量拉取
增量拉取发生:当列表不为 null ,只拉取 eureka-server 的修改的数据(注册新的服务, 上线服务)
eureka 客户端会把服务列表缓存到本地 为了提高性能
但是有脏读问题,当你启动一个新的应用的时候 不会被老的应用快速发现,毕竟eureka相比于zookeeper,放弃的就是一致性,选择的是高可用,也就是AP组合。
集群同步信息
集群的信息同步发生在eureka-server服务端之间。
在执行register方法注册微服务实例完成后,执行了集群信息同步方法replicateToPeers
首先,判断是否有节点,然后遍历集群节点,用以给各个集群信息节点进行信息同步。
然后,调用replicateInstanceActionsToPeers方法,在该方法中根据具体的操作类型Action,选择分支,最终调用PeerEurekaNode的register方法:
这个后面调用了一个post请求
之后post请求发送完毕之后,进行判断
最后如果是集群模式,那么就会把集群同步的表示isReplication设定为true,说明注册的信息是来自于集群同步。
在注册过程中运行到addInstance方法时,单独注册时isReplication的值为false,集群同步时为true。通过该值,能够避免集群间出现死循环,进行循环同步的问题。