服务注册接口源码分析:

com.netflix.eureka.resources.ApplicationResource#addInstance

public Response addInstance(InstanceInfo info,
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
//注册
registry.register(info, "true".equals(isReplication));
return Response.status(204).build(); // 204 to be backwards compatible
}

com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#register

public void register(final InstanceInfo info, final boolean isReplication) {
// 心跳检测周期默认90s
int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
// 配置文件设置该时间,就用配置文件的设置时间
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
// 调用父方法
super.register(info, leaseDuration, isReplication);
// 复制到集群其他节点
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
}

com.netflix.eureka.registry.AbstractInstanceRegistry#register

public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
try {
read.lock();
// 从注册表中获取实例信息
Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
REGISTER.increment(isReplication);
// 第一次注册时,gMap是null
if (gMap == null) {
// 定义一个Map
final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>();
// 进行put操作
gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
// 根据实例ID获取注册信息,第一次注册获取为空
Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
// 不为空,说明已注册但实例信息发生变化
if (existingLease != null && (existingLease.getHolder() != null)) {
Long existingLastDirtyTimestamp = 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 = existingLease.getHolder();
}
} else {
// 该租约不存在,因此它是一个新的注册
synchronized (lock) {
if (this.expectedNumberOfClientsSendingRenews > 0) {
// 因为客户机想要注册它,所以要增加发送更新的客户机的数量
this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews + 1;
updateRenewsPerMinThreshold();
}
}
logger.debug("No previous lease information found; it is new registration");
}
Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration);
if (existingLease != null) {
lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
}
// 将实例信息加入map中
gMap.put(registrant.getId(), lease);
synchronized (recentRegisteredQueue) {
recentRegisteredQueue.add(new Pair<Long, String>(
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 (!overriddenInstanceStatusMap.containsKey(registrant.getId())) {
logger.info("Not found overridden id {} and hence adding it", registrant.getId());
overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
}
}
InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(registrant.getId());
if (overriddenStatusFromMap != null) {
logger.info("Storing overridden status {} from map", overriddenStatusFromMap);
registrant.setOverriddenStatus(overriddenStatusFromMap);
} InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication);
registrant.setStatusWithoutDirty(overriddenInstanceStatus); if (InstanceStatus.UP.equals(registrant.getStatus())) {
lease.serviceUp();
}
registrant.setActionType(ActionType.ADDED);
recentlyChangedQueue.add(new RecentlyChangedItem(lease));
registrant.setLastUpdatedTimestamp();
invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
logger.info("Registered instance {}/{} with status {} (replication={})",
registrant.getAppName(), registrant.getId(), registrant.getStatus(), isReplication);
} finally {
read.unlock();
}
}

com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateToPeers

将注册信息同步到集群中其他节点

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 (peerEurekaNodes == Collections.EMPTY_LIST || isReplication) {
return;
} for (final PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) {
// 如果url表示此主机,则不要复制到自己.
if (peerEurekaNodes.isThisMyUrl(node.getServiceUrl())) {
continue;
}
// 复制操作
replicateInstanceActionsToPeers(action, appName, id, info, newStatus, node);
}
} finally {
tracer.stop();
}
}

com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateInstanceActionsToPeers

复制操作

private void replicateInstanceActionsToPeers(Action action, String appName,
String id, InstanceInfo info, InstanceStatus newStatus,
PeerEurekaNode node) {
try {
InstanceInfo infoFromRegistry = null;
CurrentRequestVersion.set(Version.V2);
switch (action) {
case Cancel: // 下线
node.cancel(appName, id);
break;
case Heartbeat://心跳
InstanceStatus overriddenStatus = overriddenInstanceStatusMap.get(id);
infoFromRegistry = getInstanceByAppAndId(appName, id, false);
node.heartbeat(appName, id, infoFromRegistry, overriddenStatus, false);
break;
case Register://注册
node.register(info);
break;
case StatusUpdate:// 状态更新
infoFromRegistry = getInstanceByAppAndId(appName, id, false);
node.statusUpdate(appName, id, newStatus, infoFromRegistry);
break;
case DeleteStatusOverride:
infoFromRegistry = getInstanceByAppAndId(appName, id, false);
node.deleteStatusOverride(appName, id, infoFromRegistry);
break;
}
} catch (Throwable t) {
logger.error("Cannot replicate information to {} for action {}", node.getServiceUrl(), action.name(), t);
}
}

微服务笔记之Eureka03(服务注册分析)的更多相关文章

  1. Spring Cloud微服务笔记(二)Spring Cloud 简介

    Spring Cloud 简介 Spring Cloud的设计理念是Integrate Everything,即充分利用现有的开源组件, 在它们之上设计一套统一的规范/接口使它们能够接入Spring ...

  2. 用Nacos做微服务架构里的服务注册与发现中心

    转自:https://www.jianshu.com/p/61608ff86344 Nacos 另一个非常重要的特性就是服务注册与发现,说到服务的注册与发现相信大家应该都不陌生,在微服务盛行的今天,服 ...

  3. # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...

  4. 微服务~Eureka实现的服务注册与发现及服务之间的调用

    微服务里一个重要的概念就是服务注册与发现技术,当你有一个新的服务运行后,我们的服务中心可以感知你,然后把加添加到服务列表里,然后当你死掉后,会从服务中心把你移除,而你作为一个服务,对其它服务公开的只是 ...

  5. Spring Cloud微服务笔记(三)服务治理:Spring Cloud Eureka快速入门

    服务治理:Spring Cloud Eureka 一.服务治理 服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册与发现. 1.服务注册: 在服务治理框架中,通常会构 ...

  6. 微服务Consul系列之服务注册与服务发现

    在进行服务注册之前先确认集群是否建立,关于服务注册可以看上篇微服务Consul系列之集群搭建的介绍,两种注册方式:一种是注册HTTP API.另一种是通过配置文件定义,下面讲解的是基于后者配置文件定义 ...

  7. 微服务通信之feign的注册、发现过程

    前言 feign 是目前微服务间通信的主流方式,是springCloud中一个非常重要的组件.他涉及到了负载均衡.限流等组件.真正意义上掌握了feign可以说就掌握了微服务. 一.feign的使用 f ...

  8. 2021升级版微服务教程4—Nacos 服务注册和发现

    2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 默认文件1610014380163 教程全目录「含视 ...

  9. 微服务(三) Eureka注册中心和Ribbon负载均衡

    1. Eureka注册中心 1.1 Eureka的结构和作用 在上一篇文章中 微服务(二)服务拆分及远程调用 order-service在发起远程调用的时候,该如何得知user-service实例的i ...

  10. 读书笔记--大规模web服务开发技术

    总评        这本书是日本一个叫hatena的大型网站的CTO写的,通过hatena网站从小到大的演进来反应一个web系统从小到大过程中的各种系统和技术架构变迁,比较接地气.      书的内容 ...

随机推荐

  1. Mybatis理解

    MyBatis学习及理解 1.Mybatis简介 MyBatis是一款优秀的持久层框架,他支持定制化SQL文件.存储过程以及高级映射.避免了JDBC代码和手动设置参数以及获取结果集,Mybatis可以 ...

  2. Windows 映射网络驱动器及删除-此网格连接不存在

    将共享目录,映射到本地磁盘,可以方便快速访问 添加 点击[此电脑]菜单栏中,选择[计算机]->[映射网格驱动器]-> 文件夹中输入 共享目录地址,如下图 删除 右击,网格映射盘,右击[断开 ...

  3. drf-day3——drf整体流程、APIView执行流程及源码分析、Request对象源码分析、序列化器介绍和使用、反序列化的使用、反序列化的校验

    目录 一.drf 整体内容 二.APIView执行流程--源码分析(难,了解) 2.1 基于APIView+JsonResponse编写接口 2.2 基于APIView+Response 写接口 2. ...

  4. mapreduce的使用

    mapreduce的使用 以下案例写之前需要导入jar包依赖: <dependencies> <dependency> <groupId>org.apache.ha ...

  5. JZOJ 2022.02.11【提高A组】模拟

    \(\text{Solution}\) 首先把 \(T2\) 给切了,\(T1\) 找半天规律找不到 然后打了个表算是暴力了 \(T3\) 也暴... 太暴了... \(T4\) 直接啥也不会 \(\ ...

  6. Hbase一:Hbase介绍及特点

    转载请注明出处: 1.Google的三篇论文 2003年,Google发布Google File System论文,(GFS)这是一个可扩展的分布 式文件系统,用于大型的.分布式的.对大量数据进行访问 ...

  7. EULAR2021_推文_大多数免疫抑制剂对辉瑞新冠疫苗效果影响小

    尤其令人开心的是TNF抑制剂和抗IL-17!但是,糖皮质激素.利妥昔单抗.吗替麦考酚酯(MMF).阿巴西普(抑制T淋巴细胞激活)会明显降低疫苗接种效果.链接:http://note.youdao.co ...

  8. 组织炎症水平高的RA患者接受TNF拮抗剂治疗的效果更好

    组织炎症水平高的RA患者接受TNF拮抗剂治疗的效果更好van der Pouw Kraan TC, et al. Ann Rheum Dis. 2008;67(4):563-6.目的:不同患者对TNF ...

  9. video遇到问题汇总

    1.调取视频自动播放video.play()时报错 Uncaught (in promise) DOMException: play() failed because the user didn't ...

  10. nodejs 接收参数,js前端传参方法

    nodejs // 接口:查询检测结果 req.query接收 router.get('/getDetectionResult', (req, res) => { console.log(req ...