SpringCloud源码剖析-Eureka Server服务下线

简介: 1.从registry中移除服务,2.从overriddenInstanceStatusMap状态map中移除服务状态3.添加到最近取消队列4.调用Lease.cancel方法,将租约对象中的逐出时间修改为当前时间5.修改服务的InstanceInfo的状态为DELETE6.添加到最近修改队列7.更新服务最后修改时间8.使ReponseCache缓存无

Eureka Server 服务下线

在《Eureka Client取消注册》中我们有分析到,当Eureka Client 客户端当服务关闭,触发客户端服务下线方法,客户端执行一系列下线逻辑后会向Eureka Server服务端发送服务下线请求,服务端处理下线的请求是在com.netflix.eureka.resources.InstanceResource#cancelLease方法中

/**处理此特定实例的租赁取消* Handles cancellation of leases for this particular instance.** @param isReplication*            a header parameter containing information whether this is*            replicated from other nodes.* @return response indicating whether the operation was a success or*         failure.*/@DELETEpublicResponsecancelLease(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) StringisReplication) {
try {
//调用 InstanceRegistry的 cancel 方法下线服务booleanisSuccess=registry.cancel(app.getName(), id,
"true".equals(isReplication));
if (isSuccess) {
logger.debug("Found (Cancel): {} - {}", app.getName(), id);
returnResponse.ok().build();
        } else {
logger.info("Not Found (Cancel): {} - {}", app.getName(), id);
returnResponse.status(Status.NOT_FOUND).build();
        }
    } catch (Throwablee) {
logger.error("Error (cancel): {} - {}", app.getName(), id, e);
returnResponse.serverError().build();
    }
}

InstanceRegistry的 cancel 方法

publicclassInstanceRegistryextendsPeerAwareInstanceRegistryImplimplementsApplicationContextAware {
@Overridepublicbooleancancel(StringappName, StringserverId, booleanisReplication) {
//抛出EurekaInstanceCanceledEvent取消事件handleCancelation(appName, serverId, isReplication);
//调用PeerAwareInstanceRegistryImpl#cancelreturnsuper.cancel(appName, serverId, isReplication);
   }
//抛出EurekaInstanceCanceledEvent取消事件privatevoidhandleCancelation(StringappName, Stringid, booleanisReplication) {
log("cancel "+appName+", serverId "+id+", isReplication "+isReplication);
publishEvent(newEurekaInstanceCanceledEvent(this, appName, id, isReplication));
   }

这里比较简单,抛出EurekaInstanceCanceledEvent时间后调用super(PeerAwareInstanceRegistryImpl)的下线方法

/** (non-Javadoc)** @see com.netflix.eureka.registry.InstanceRegistry#cancel(java.lang.String,* java.lang.String, long, boolean)*/@Overridepublicbooleancancel(finalStringappName, finalStringid,
finalbooleanisReplication) {
//调用super.cancel下线方法:com.netflix.eureka.registry.AbstractInstanceRegistry#cancelif (super.cancel(appName, id, isReplication)) {
//复制到其他的Eureka节点replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
synchronized (lock) {
if (this.expectedNumberOfRenewsPerMin>0) {
//如果每分钟的预期续订次数大于0//由于客户想取消该阈值,因此降低阈值(1次 30秒,2次 1分钟)// Since the client wants to cancel it, reduce the threshold (1 for 30 seconds, 2 for a minute)//预期续订次数 = 预期续订次数 -2 (2次 1分钟 , 1次 30)this.expectedNumberOfRenewsPerMin=this.expectedNumberOfRenewsPerMin-2;
//续订次数阈值  = 预期续订次数  * 0.85this.numberOfRenewsPerMinThreshold=                    (int) (this.expectedNumberOfRenewsPerMin*serverConfig.getRenewalPercentThreshold());
            }
        }
returntrue;
    }
returnfalse;
}

这里继续调用super.cancel(AbstractInstanceRegistry#cancel),完成下线后重新计算了续约阈值,继续看AbstractInstanceRegistry#cancel方法

publicabstractclassAbstractInstanceRegistryimplementsInstanceRegistry {
/**//取消实例注册//这通常是由客户端调用时关闭通知服务器从流量中除去实例* Cancels the registration of an instance.** <p>* This is normally invoked by a client when it shuts down informing the* server to remove the instance from traffic.* </p>** @param appName the application name of the application.* @param id the unique identifier of the instance.* @param isReplication true if this is a replication event from other nodes, false*                      otherwise.* @return true if the instance was removed from the {@link AbstractInstanceRegistry} successfully, false otherwise.*/@Overridepublicbooleancancel(StringappName, Stringid, booleanisReplication) {
returninternalCancel(appName, id, isReplication);
    }
/**内部取消服务注册* {@link #cancel(String, String, boolean)} method is overridden by {@link PeerAwareInstanceRegistry}, so each* cancel request is replicated to the peers. This is however not desired for expires which would be counted* in the remote peers as valid cancellations, so self preservation mode would not kick-in.*/protectedbooleaninternalCancel(StringappName, Stringid, booleanisReplication) {
try {
//上锁read.lock();
//服务取消数增加CANCEL.increment(isReplication);
//获取当前提出的服务Map<String, Lease<InstanceInfo>>gMap=registry.get(appName);
Lease<InstanceInfo>leaseToCancel=null;
if (gMap!=null) {
//从服务注册的map中移除掉当前服务leaseToCancel=gMap.remove(id);
            }
//添加到最近取消队列synchronized (recentCanceledQueue) {
recentCanceledQueue.add(newPair<Long, String>(System.currentTimeMillis(), appName+"("+id+")"));
            }
//overriddenInstanceStatusMap 服务状态map中移除当前服务InstanceStatusinstanceStatus=overriddenInstanceStatusMap.remove(id);
if (instanceStatus!=null) {
logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
            }
if (leaseToCancel==null) {
//没找到服务CANCEL_NOT_FOUND.increment(isReplication);
logger.warn("DS: Registry: cancel failed because Lease is not registered for: {}/{}", appName, id);
returnfalse;
            } else {
//调用Lease.cancel方法leaseToCancel.cancel();
//获取服务实例信息InstanceInfoinstanceInfo=leaseToCancel.getHolder();
Stringvip=null;
Stringsvip=null;
if (instanceInfo!=null) {
//实例状态修改为删除instanceInfo.setActionType(ActionType.DELETED);
//添加最近修改队列recentlyChangedQueue.add(newRecentlyChangedItem(leaseToCancel));
//实例信息对象修改最后修改时间instanceInfo.setLastUpdatedTimestamp();
vip=instanceInfo.getVIPAddress();
svip=instanceInfo.getSecureVipAddress();
                }
//使缓存无效,调用responseCache.invalidate让服务在缓存中失效invalidateCache(appName, vip, svip);
logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
returntrue;
            }
        } finally {
read.unlock();
        }
    }
}

AbstractInstanceRegistry的cancel方法中调用了internalCancel去取消服务的注册,其实在之间分析服务剔除的时候也嗲用这个方法,方法的逻辑大致是:

  • 1.从registry中移除服务,
  • 2.从overriddenInstanceStatusMap状态map中移除服务状态
  • 3.添加到最近取消队列
  • 4.调用Lease.cancel方法,将租约对象中的逐出时间修改为当前时间
  • 5.修改服务的InstanceInfo的状态为DELETE
  • 6.添加到最近修改队列
  • 7.更新服务最后修改时间
  • 8.使ReponseCache缓存无效

总结

我们发现,Eureka Server服务剔除和服务下线的流程后半截很相似,一个是通过定时任务来实现服务端过期的服务的剔除,一个是客户端发送请求到服务端剔除指定的服务,都是走服务下线逻辑

目录
相关文章
|
22天前
|
消息中间件 存储 Java
SpringCloud基础9——服务异步通信-高级篇
消息可靠性、死信交换机、惰性队列、MQ集群
SpringCloud基础9——服务异步通信-高级篇
|
10天前
|
Java API 对象存储
微服务魔法启动!Spring Cloud与Netflix OSS联手,零基础也能创造服务奇迹!
这段内容介绍了如何使用Spring Cloud和Netflix OSS构建微服务架构。首先,基于Spring Boot创建项目并添加Spring Cloud依赖项。接着配置Eureka服务器实现服务发现,然后创建REST控制器作为API入口。为提高服务稳定性,利用Hystrix实现断路器模式。最后,在启动类中启用Eureka客户端功能。此外,还可集成其他Netflix OSS组件以增强系统功能。通过这些步骤,开发者可以更高效地构建稳定且可扩展的微服务系统。
28 1
|
22天前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
2月前
|
存储 Java Spring
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
【Azure Spring Cloud】Azure Spring Cloud服务,如何获取应用程序日志文件呢?
|
2月前
|
Java 应用服务中间件 数据库
SpringCloud:服务保护和分布式事务详解
SpringCloud:服务保护和分布式事务详解
98 0
|
10天前
|
SpringCloudAlibaba API 开发者
新版-SpringCloud+SpringCloud Alibaba
新版-SpringCloud+SpringCloud Alibaba
|
2月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
定时任务在企业应用中至关重要,常用于异步数据处理、自动化运维等场景。在单体应用中,利用Java的`java.util.Timer`或Spring的`@Scheduled`即可轻松实现。然而,进入微服务架构后,任务可能因多节点并发执行而重复。Spring Cloud Alibaba为此发布了Scheduling模块,提供轻量级、高可用的分布式定时任务解决方案,支持防重复执行、分片运行等功能,并可通过`spring-cloud-starter-alibaba-schedulerx`快速集成。用户可选择基于阿里云SchedulerX托管服务或采用本地开源方案(如ShedLock)
|
2月前
|
人工智能 前端开发 Java
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
本文介绍了如何使用 **Spring Cloud Alibaba AI** 构建基于 Spring Boot 和 uni-app 的聊天机器人应用。主要内容包括:Spring Cloud Alibaba AI 的概念与功能,使用前的准备工作(如 JDK 17+、Spring Boot 3.0+ 及通义 API-KEY),详细实操步骤(涵盖前后端开发工具、组件选择、功能分析及关键代码示例)。最终展示了如何成功实现具备基本聊天功能的 AI 应用,帮助读者快速搭建智能聊天系统并探索更多高级功能。
594 2
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
|
8天前
|
人工智能 前端开发 Java
Spring Cloud Alibaba AI,阿里AI这不得玩一下
🏀闪亮主角: 大家好,我是JavaDog程序狗。今天分享Spring Cloud Alibaba AI,基于Spring AI并提供阿里云通义大模型的Java AI应用。本狗用SpringBoot+uniapp+uview2对接Spring Cloud Alibaba AI,带你打造聊天小AI。 📘故事背景: 🎁获取源码: 关注公众号“JavaDog程序狗”,发送“alibaba-ai”即可获取源码。 🎯主要目标:
17 0
|
2月前
|
Java 微服务 Spring
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
文章介绍了如何利用Spring Cloud Alibaba快速构建大型电商系统的分布式微服务,包括服务限流降级等主要功能的实现,并通过注解和配置简化了Spring Cloud应用的接入和搭建过程。
SpringBoot+Vue+Spring Cloud Alibaba 实现大型电商系统【分布式微服务实现】
下一篇
无影云桌面