Eureka服务注册发现源码流程简析

news/2025/3/12 17:24:31/文章来源:https://www.cnblogs.com/sansWL/p/18764933

一: 服务的注册

客户端通过执行InstanceInfoReplicator#run()调用DiscoveryClient#register()发送http请求进行注册
InstanceInfoReplicator 是同于更新同步当前服务到服务端的任务实现
//A task for updating and replicating the local instanceinfo to the remote server.

//服务注册
boolean register() throws Throwable {logger.info("DiscoveryClient_{}: registering service...", this.appPathIdentifier);EurekaHttpResponse httpResponse;try {httpResponse = this.eurekaTransport.registrationClient.register(this.instanceInfo);} catch (Exception var3) {Exception e = var3;logger.warn("DiscoveryClient_{} - registration failed {}", new Object[]{this.appPathIdentifier, e.getMessage(), e});throw e;}if (logger.isInfoEnabled()) {logger.info("DiscoveryClient_{} - registration status: {}", this.appPathIdentifier, httpResponse.getStatusCode());}return httpResponse.getStatusCode() == Status.NO_CONTENT.getStatusCode();}
//服务续约
/**
eureka 初始化定时任务,依据设定的心跳时间触发 renew方法,检测服务是否宕机
*/boolean renew() {try {EurekaHttpResponse<InstanceInfo> httpResponse = this.eurekaTransport.registrationClient.sendHeartBeat(this.instanceInfo.getAppName(), this.instanceInfo.getId(), this.instanceInfo, (InstanceInfo.InstanceStatus)null);logger.debug("DiscoveryClient_{} - Heartbeat status: {}", this.appPathIdentifier, httpResponse.getStatusCode());if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {this.REREGISTER_COUNTER.increment();logger.info("DiscoveryClient_{} - Re-registering apps/{}", this.appPathIdentifier, this.instanceInfo.getAppName());long timestamp = this.instanceInfo.setIsDirtyWithTime();boolean success = this.register();if (success) {this.instanceInfo.unsetIsDirty(timestamp);}return success;} else {return httpResponse.getStatusCode() == Status.OK.getStatusCode();}} catch (Throwable var5) {Throwable e = var5;logger.error("DiscoveryClient_{} - was unable to send heartbeat!", this.appPathIdentifier, e);return false;}}

服务端服务注册接受和存储

//eureka 客户端会通过此方法注册保存到eureka server 的内存中
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {this.read.lock();try {Map<String, Lease<InstanceInfo>> gMap = (Map)this.registry.get(registrant.getAppName());EurekaMonitors.REGISTER.increment(isReplication);if (gMap == null) {ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap();gMap = (Map)this.registry.putIfAbsent(registrant.getAppName(), gNewMap);if (gMap == null) {gMap = gNewMap;}}Lease<InstanceInfo> existingLease = (Lease)((Map)gMap).get(registrant.getId());if (existingLease != null && existingLease.getHolder() != null) {Long existingLastDirtyTimestamp = ((InstanceInfo)existingLease.getHolder()).getLastDirtyTimestamp();Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp) {logger.warn("There is an existing lease and the existing lease's dirty timestamp {} is greater than the one that is being registered {}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);logger.warn("Using the existing instanceInfo instead of the new instanceInfo as the registrant");registrant = (InstanceInfo)existingLease.getHolder();}} else {synchronized(this.lock) {if (this.expectedNumberOfClientsSendingRenews > 0) {++this.expectedNumberOfClientsSendingRenews;this.updateRenewsPerMinThreshold();}}logger.debug("No previous lease information found; it is new registration");}Lease<InstanceInfo> lease = new Lease(registrant, leaseDuration);if (existingLease != null) {lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());}((Map)gMap).put(registrant.getId(), lease);this.recentRegisteredQueue.add(new Pair(System.currentTimeMillis(), registrant.getAppName() + "(" + registrant.getId() + ")"));if (!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) {logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the overrides", registrant.getOverriddenStatus(), registrant.getId());if (!this.overriddenInstanceStatusMap.containsKey(registrant.getId())) {logger.info("Not found overridden id {} and hence adding it", registrant.getId());this.overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());}}InstanceInfo.InstanceStatus overriddenStatusFromMap = (InstanceInfo.InstanceStatus)this.overriddenInstanceStatusMap.get(registrant.getId());if (overriddenStatusFromMap != null) {logger.info("Storing overridden status {} from map", overriddenStatusFromMap);registrant.setOverriddenStatus(overriddenStatusFromMap);}InstanceInfo.InstanceStatus overriddenInstanceStatus = this.getOverriddenInstanceStatus(registrant, existingLease, isReplication);registrant.setStatusWithoutDirty(overriddenInstanceStatus);if (InstanceStatus.UP.equals(registrant.getStatus())) {lease.serviceUp();}registrant.setActionType(ActionType.ADDED);this.recentlyChangedQueue.add(new RecentlyChangedItem(lease));registrant.setLastUpdatedTimestamp();this.invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());logger.info("Registered instance {}/{} with status {} (replication={})", new Object[]{registrant.getAppName(), registrant.getId(), registrant.getStatus(), isReplication});} finally {this.read.unlock();}}

如图,registry保存有将注册、已注册到server 的eureka客户端 instance信息;
将要注册到注册表registry中的instance,会创建一个map结构保存

二: 服务的发现

依据上图展示,服务注册采取的是客户端创立DiscoveryClient建立http请求,同理利用此DiscoveryClient实例通过请求完成服务的发现,不再赘述;
重点将放入服务发现的缓存和调用

1.

//其他发现实现 DiscoveryClient#getAndUpdateDelta 包括更新等具体操作不作继续深入讨论/*** Gets the full registry information from the eureka server and stores it locally.* When applying the full registry, the following flow is observed:** if (update generation have not advanced (due to another thread))*   atomically set the registry to the new registry* fi** @return the full registry information.* @throws Throwable*             on error.*/private void getAndStoreFullRegistry() throws Throwable {long currentUpdateGeneration = fetchRegistryGeneration.get();logger.info("Getting all instance registry info from the eureka server");Applications apps = null;EurekaHttpResponse<Applications> httpResponse = clientConfig.getRegistryRefreshSingleVipAddress() == null? eurekaTransport.queryClient.getApplications(remoteRegionsRef.get()): eurekaTransport.queryClient.getVip(clientConfig.getRegistryRefreshSingleVipAddress(), remoteRegionsRef.get());if (httpResponse.getStatusCode() == Status.OK.getStatusCode()) {apps = httpResponse.getEntity();}logger.info("The response status is {}", httpResponse.getStatusCode());if (apps == null) {logger.error("The application is null for some reason. Not storing this information");} else if (fetchRegistryGeneration.compareAndSet(currentUpdateGeneration, currentUpdateGeneration + 1)) {//存入本地服务缓存,即客户端将server端的服务注册信息缓存了一份,存在后续的缓存更新机制不做深入//this.filterAndShuffle(apps) 目的是处理 UP 状态的实例以及 打乱保证随机性 // Shuffling helps in randomizing the applications list there by avoiding the same instances receiving traffic during start ups.localRegionApps.set(this.filterAndShuffle(apps));logger.debug("Got full registry with apps hashcode {}", apps.getAppsHashCode());} else {logger.warn("Not updating applications as another thread is updating it already");}}

2. 调用

一: 利用DiscoveryClient获取实例的信息,再构建http请求
二: 使用组件fegin完成服务转发

@FeignClient(value = "eurekaclient")
public interface ApiService {@RequestMapping(value = "/index",method = RequestMethod.GET)String index();
}/**
等价于 new httpclient(eurekaClient) => 发送 /index 接口并接受到response
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/897280.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高等数学笔记

唉...本蒟蒻也是要考研了, 目前目标是深圳大学, 想研究的方向偏算法多一点, 深度学习强化学习什么的, 我会尽最大努力了 9 做到一个新的问题,想起与过去某个问题类似。发现在解答中,对此类问题,以及工具和方法的理解是存在缺陷的,或者发现理解不够深刻。于是通过解决新的…

Scatter(A Distance-Guided Fuzzing For Heap-layout)

SCATTER Abstract 利用堆利用的方法为将受害者的chunk放在可以溢出的chunk之后。SCATTER使能够以无原始的方式以普通purpose程序中的堆溢出产生可剥削的堆布局。它先使用静态分析和动态检测来计算潜在的堆利用布局,然后设计由新操纵距离为指导的fuzz,该距离衡量了在堆布局空间…

使用 Pixi.js 插件实现探险者小游戏(二)

使用 Pixi.js 插件实现探险者小游戏(一)中我们学习了如何创建精灵图,这节我们要让精灵图动起来。 精灵图布局 游戏画面如下图所示,我们要生成一个围墙,探险者、恶魔、宝物都在这个围墙里面。探险者可以上下左右移动,恶魔只能上下移动,宝物是不动的。探险者与宝物被恶魔群…

Docker:CentOS 7 离线安装 docker-ce

0. 检查卸载已有docker 查看是否安装 docker yum list installed | grep docker 卸载docker yum remove docker docker-common container-selinux docker-selinux docker-engineyum remove -y docker-* 1. 下载安装包 要下载docker-18.06.x-ce版本,否则有些不支持 k8s。。请看…

dp泄露攻击

题目: from Crypto.Util.number import *flag = bNSSCTF{******} + b1*100p = getPrime(512) q = getPrime(512)n = p*q e = 65537 d = inverse(e, (p-1)*(q-1))dp = d % (p-1)m = bytes_to_long(flag)c = pow(m, e, n)print(fn = {n}) print(fc = {c}) print(fdp = {dp}) n = …

dpdq泄露攻击-没e_

题目: from Crypto.Util.number import * from gmpy2 import * from secret import flagp = getPrime(1024) q = getPrime(1024) d = inverse(65537,(p-1)*(q-1)) dp = d%(p-1) dq = d%(q-1) print(fc={pow(bytes_to_long(flag),e,p*q)}) print(fp={p}) print(fq={q}) print(fd…

Linux安装Ollama服务

背景 Ollama官方提供了一键式安装脚本,但因国内网络问题,效率太低,所以探索更为快捷方式。 我的系统信息如下 root@yan:/mnt/d/data# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.5 LTS Release: 22.04 Code…

C学习笔记-311

多维数组和指针 为什么需要数组为了解决大量同类型数据的存储和使用问题。 用数组可以模拟现实世界。Int a[25]:一维数组,可以当做一个线性结构。 Int a[8][6]:可以当做一个平面,意思是8行6列。有48个元素。 Int a[3][4][5]:可以当做一个三维立体。 Int a[3][4][5][6]:可…

e与(p-1)或(q-1)均不互素

题目: from Crypto.Util.number import bytes_to_long from secret import flage = 0x14 p = 7330895897249035860738209657929637460767893905398244379628076799548083100726568174238286139385106848645676643457511649442694896479642275193079806880680590593771233914993…

e与(q-1)互素,但用上题方法求不出

题目: c = 2485360255306619684345131431867350432205477625621366642887752720125176463993839766742234027524 n = 0x2CAA9C09DC1061E507E5B7F39DDE3455FCFE127A2C69B621C83FD9D3D3EAA3AAC42147CD7188C53 e = 3解题思路:分解n得到分析得到e只与(r-1)互素,但用上题方法无法解出…

张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫

目录什么是 Selenium环境搭建与配置安装 Selenium下载浏览器驱动基础操作启动浏览器并访问网页定位网页元素通过 ID 定位通过 CSS 选择器定位通过 XPath 定位与元素交互提取数据交互操作设置等待时间切换页面执行 JavaScript 代码关闭浏览器进阶技巧使用 ActionChains 模拟用户…