Cancel(服务下线)

在Service Provider服务shut down的时候,需要及时通知Eureka Server把自己剔除,从而避免其它客户端调用已经下线的服务,导致服务不可用。

com.netflix.discovery.DiscoveryClient中shutdown()的867行。

/**
* Shuts down Eureka Client. Also sends a deregistration request to the
* eureka server.
*/
@PreDestroy
@Override
public synchronized void shutdown() {
if (isShutdown.compareAndSet(false, true)) {
logger.info("Shutting down DiscoveryClient ...");
if (statusChangeListener != null && applicationInfoManager != null) {
applicationInfoManager.unregisterStatusChangeListener(statusChangeListener.getId());
}
cancelScheduledTasks();
// If APPINFO was registered
if (applicationInfoManager != null && clientConfig.shouldRegisterWithEureka()) {
applicationInfoManager.setInstanceStatus(InstanceStatus.DOWN);
//调用下线接口
unregister();
}
if (eurekaTransport != null) {
eurekaTransport.shutdown();
}
heartbeatStalenessMonitor.shutdown();
registryStalenessMonitor.shutdown();
logger.info("Completed shut down of DiscoveryClient");
}
}

@PreDestroy注解或shutdown()的方法是服务下线的入口

com.netflix.discovery.DiscoveryClientunregister()897

void unregister() {
// It can be null if shouldRegisterWithEureka == false
if(eurekaTransport != null && eurekaTransport.registrationClient != null) {
try {
logger.info("Unregistering ...");
//发送服务下线请求
EurekaHttpResponse<Void> httpResponse = eurekaTransport.registrationClient.cancel(instanceInfo.getAppName(), instanceInfo.getId());
logger.info(PREFIX + appPathIdentifier + " - deregister status: " + httpResponse.getStatusCode());
} catch (Exception e) {
logger.error(PREFIX + appPathIdentifier + " - de-registration failed" + e.getMessage(), e);
}
}
}

Eureka Server服务下线实现细节

  1. com.netflix.eureka.resources.InstanceResource中的280行中的cancelLease()方法

@DELETE
public Response cancelLease(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
//调用cancel
boolean isSuccess = registry.cancel(app.getName(), id,
"true".equals(isReplication));
if (isSuccess) {
logger.debug("Found (Cancel): " + app.getName() + " - " + id);
return Response.ok().build();
} else {
logger.info("Not Found (Cancel): " + app.getName() + " - " + id);
return Response.status(Status.NOT_FOUND).build();
}
}

com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl中的376

@Override
public boolean cancel(final String appName, final String id,
final boolean isReplication) {
if (super.cancel(appName, id, isReplication)) {
//服务下线成功后,同步更新信息到其它Eureka Server节点
replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
synchronized (lock) {
if (this.expectedNumberOfRenewsPerMin > 0) {
// Since the client wants to cancel it, reduce the threshold (1 for 30 seconds, 2 for a minute)
this.expectedNumberOfRenewsPerMin = this.expectedNumberOfRenewsPerMin - 2;
this.numberOfRenewsPerMinThreshold =
(int) (this.expectedNumberOfRenewsPerMin * serverConfig.getRenewalPercentThreshold());
}
}
return true;
}
return false;
}

在com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl中的618行,主要接口实现方式和register基本一致:首先更新自身Eureka Server中服务的状态,再同步到其它Eureka Server中。

private void replicateToPeers(Action action, String appName, String id,
InstanceInfo info /* optional */,
InstanceStatus newStatus /* optional */, boolean isReplication) {
Stopwatch tracer = action.getTimer().start();
try {
if (isReplication) {
numberOfReplicationsLastMin.increment();
}
// If it is a replication already, do not replicate again as this will create a poison replication
if (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
return;
}
// 同步把服务信息同步到其它的Eureka Server中
for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
// If the url represents this host, do not replicate to yourself.
if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
continue;
}
//根据action做相应操作的同步
replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
}
} finally {
tracer.stop();
}
}

Eureka服务下线(Cancel)源码分析的更多相关文章

  1. Netty 心跳服务之 IdleStateHandler 源码分析

    前言:Netty 提供的心跳介绍 Netty 作为一个网络框架,提供了诸多功能,比如我们之前说的编解码,Netty 准备很多现成的编解码器,同时,Netty 还为我们准备了网络中,非常重要的一个服务- ...

  2. 【一起学源码-微服务】Nexflix Eureka 源码九:服务续约源码分析

    前言 前情回顾 上一讲 我们讲解了服务发现的相关逻辑,所谓服务发现 其实就是注册表抓取,服务实例默认每隔30s去注册中心抓取一下注册表增量数据,然后合并本地注册表数据,最后有个hash对比的操作. 本 ...

  3. SpringCloud(4)---Ribbon服务调用,源码分析

    SpringCloud(4)---Ribbon 本篇模拟订单服务调用商品服务,同时商品服务采用集群部署. 注册中心服务端口号7001,订单服务端口号9001,商品集群端口号:8001.8002.800 ...

  4. Netty源码分析 (三)----- 服务端启动源码分析

    本文接着前两篇文章来讲,主要讲服务端类剩下的部分,我们还是来先看看服务端的代码 /** * Created by chenhao on 2019/9/4. */ public final class ...

  5. Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析

    什么是心跳机制? 心跳说的是在客户端和服务端在互相建立ESTABLISH状态的时候,如何通过发送一个最简单的包来保持连接的存活,还有监控另一边服务的可用性等. 心跳包的作用 保活Q:为什么说心跳机制能 ...

  6. Netty之旅三:Netty服务端启动源码分析,一梭子带走!

    Netty服务端启动流程源码分析 前记 哈喽,自从上篇<Netty之旅二:口口相传的高性能Netty到底是什么?>后,迟迟两周才开启今天的Netty源码系列.源码分析的第一篇文章,下一篇我 ...

  7. eureka client服务续约源码分析

    必备知识: 1.定时任务 ScheduledExecutorService public class demo { public static void main(String[] args){ Sc ...

  8. ActivityManagerService服务线程启动源码分析【转】

    本文转载自:http://blog.csdn.net/yangwen123/article/details/8177702 Android系统服务线程都驻留在SystemServer进程中,由Syst ...

  9. 【springcloud】1.微服务之springcloud-》eureka源码分析之请叫我灵魂画师。。。

随机推荐

  1. anaconda安装不存在的包

    Anaconda作为一个工具包集成管理工具,下载python工具包是很方便的,直接敲: conda install package_name 1 但是有时候安装一个工具包(如skimage)的时候,在 ...

  2. python爬虫从入门到放弃(四)之 Requests库的基本使用(转)

    什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关于urllib库的使用,你会发现,其 ...

  3. Java中关于 ArrayList 和 Map 的常用遍历方法 (学习笔记,便于以后查询)

    一.学习ArrayList与Map时,关于常用遍历方法的记录如下:  二.附源码如下: package com.study.in.myself; import java.util.ArrayList; ...

  4. 【bzoj5094】硬盘检测 乱搞

    题目描述 已知从 $n$ 个不同的32位无符号整数中随机选 $m=10000$ 次所得的结果,求可能性最大的 $n$ ,其中 $n=10^k,1\le k\le 7$. 输入 第一行包含一个正整数m( ...

  5. Bellman—Ford算法思想

    ---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...

  6. BZOJ4943 & 洛谷3823 & UOJ315:[NOI2017]蚯蚓排队——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4943 http://uoj.ac/problem/315 https://www.luogu.or ...

  7. 洛谷 [SCOI2010]股票交易 | 单调性DP

    题目链接 #include<cstdio> #include<algorithm> #include<cstring> #define N 2005 using n ...

  8. Dynamic Rankings——带修改区间第k大

    三种做法:1.整体二分: 二分mid 考虑小于mid的修改的影响 但是大于mid的修改可能会干掉小于mid的一些值 所以额外把一个修改变成一个值的删除和一个值的添加 这样就相互独立了! 整体二分,树状 ...

  9. Atlantis HDU - 1542 (线段树扫描线)

    There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some ...

  10. mysql中的case when 与if else

    大神说:在sql中,能用if else  就不用case  when 下面来看看,具体为什么,没有搞清楚,如果有大神知道的提供下资料: Mysql的if既可以作为表达式用,也可在存储过程中作为流程控制 ...