Eureka作为微服务中的注册中心,为微服务集群间各个服务进行调用提供寻址的功能,有了它集群间的服务只需要指定服务名称就可以了,无需再去关心服务具体部署的服务器IP,即可正常调用。下面来对其中我们开发中会接触的主要机制的实现原理进行剖析。一些具体细节这里不做详细的分析,只关注如下2个大方向的东西:1.注册相关的机制、2.客户端和服务端的启动流程。

Eureka服务端启动流程

首先需要说明的是eureka server(后面简称服务端)是在eureka client(后面简称客户端)的基础上进一步封装的一个东西;也就是说客户端有的东西服务端也有。服务端额外多的东西就是对注册表的处理部分。它的启动流程如下:

  • 初始化环境配置;这个我们在日常开发中几乎都是使用的默认的;
  • 读取服务端的配置信息,也就是读取eureka-server.properties配置文件;由于eureka中对这种配置类采用的是面向接口的方式,因此非常好扩展,在spring中是重新实现了这些配置类接口的。
  • 构建应用管理器;读取eureka-client.properties配置文件,选择其中的部分配置,基于构造者模式创建服务实例交给应用管理器。
  • 读取eureka-client.properties配置文件构建客户端信息;这里的操作和客户端的启动流程几乎就是一样的,因此这里就不做详细说明了。
  • 创建注册表感知器registry,这个也可以称为注册表管理器。这里会维护注册表信息。
  • 创建服务端集群节点信息管理器;也就是我们配置的集群地址信息,默认10分钟检查一次。
  • 基于上面的信息创建服务端的上下文信息;这里在进行初始化的时候会对相关资源进行初始化;启动相关的定时。
  • 从其他服务端节点上拉取注册表信息;这就是为什么服务端即使配置fetchRegistry为false,依然可以正常拿到注册表信息。
  • 启动注册表感知器registry的定时;这个定时主要就是检查注册表中是否有过期的注册信息。
  • 最后进行监听器的绑定。

相关的流程图如下:

Eureka客户端启动流程

eureka客户端的启动主要就是几个定时和之后进行注册表维护的网络请求资源初始化。

  • 构建应用管理器;读取eureka-client.properties配置文件,选择其中的部分配置,基于构造者模式创建服务实例交给应用管理器。
  • 读取eureka-client.properties配置信息构建客户端的配置信息;
  • 根据上面的配置信息和应用管理器构建客户端;
  • 创建心跳、缓存等需要的线程池;
  • 创建网络通信组件;后面发送注册信息、心跳信息这些请求都是通过它来处理的;
  • 判断是否需要拉取注册表信息,若是则会全量拉取一次注册表信息;
  • 启动相关的定时任务:注册表更新任务(默认30s执行一次)、心跳定时任务(默认30s执行一次)、创建服务状态更新定时任务(默认30s执行一次,这个就是留个我们自定义服务上下线状态的判断逻辑的);
  • 启动服务状态更新定时任务(第一次延迟40s执行);这里面就是向服务端发送注册信息的实现。
  • 最后进行监听器的绑定。

相关的流程图如下:

Eureka注册表的原理

eureka的注册表中保存中服务的注册信息,下面我们通过如下几个点来对其原理进行简析。

注册表抓取和缓存机制

其基本流程图如下:

注册表的数据结构和缓存机制

eureka server中对注册表的信息进行多重缓存,分为:

  • 只读缓存(ConcurrentMap):会有定时任务默认每隔30s主动的去和读写缓存里面的信息同步一次;
  • 读写缓存(guava的LoadingCache):在创建LoadingCache的时候默认设置的过期时间是180s;
  • 注册表:这个就是实时的本地注册信息,每次客户端的注册信息更新后,都会实时的保存在这里;同时在更新它的时候会将读写缓存中的值设置为失效状态。

注册表信息读取流程

注册表的拉取分为全量和增量;在初次拉取时使用的是全量,后面使用的都是增量拉取的。

全量拉取流程:

  • 服务端收到客户端的请求后,会直接从只读缓存里面取值,如果有就返回,否则进行下一步;
  • 只读缓存里面没有时,会从读写缓存里面取值,如果有就返回,同时将其设置达到只读缓存里面;否则进行下一步;
  • 读写缓存里面没有时,会触发LoadingCache的load方法,这里面会从本地注册表中取值返回。

增量拉取流程:

  • 服务端收到客户端的请求后,会直接从只读缓存里面取增量信息,如果有就返回,否则进行下一步;
  • 只读缓存里面没有时,会从读写缓存里面取增量信息,如果有就返回,同时将其设置达到只读缓存里面;否则进行下一步;
  • 读写缓存里面没有时,会触发LoadingCache的load方法,这里面会增量队列中获取变化的信息然后返回;

服务端集群间的注册信息如何同步的

要回答这个问题,我们就需要先了解客户端发送注册信息和心跳信息的整个流程,看了下面的注册和心跳流程这个问题也就可以解释了。

注册的流程来说明:

  • 客户端在启动的最后一步启动服务状态更新定时任务时,里面的定时任务就会向服务端发送注册信息;
  • 客户端会选从置的服务服务注册地址中选择第一个进行尝试,如果成功后面都会用这个,直到失败才会切换到下一个;
  • 服务端收到注册请求后,更新本地注册表中注册信息,将读写缓存中的缓存设置为失效状态;同时将注册表的变更信息保存到最近变更队列中;
  • 将注册请求信息转发给eureka server集群中的其他节点。

心跳的请求也是在服务端自己处理完成后,会自动将这个请求转发给集群中的其他节点。心跳的操作就是更新注册信息中的租约时间,这里就不详细说明了。

注意这种通知集群中其他节点的操作在失败后会不断的重试,同时正式由于有这个操作,因此服务端的fetchRegistry配置为false,集群间的注册信息依然可以正常同步的原因。

客户端的注册信息什么时候会被摘除

客户端的注册信息被摘除主要是这2种情况:1.客户端服务主动下线;2.服务异常。

客户端服务主动下线

客户端服务下线:主动取消注册信息,这种服务端直接接收请求然后删除即可;其流程图如下:

服务异常

客户端异常:没有发送取消请求或者是服务端没有正常接收和处理取消请求的情况下,此时就需要服务端自己定制一套注册信息过期机制,这也就是发送心跳的作用。

服务端中注册表信息过期检查的定时任务默认每隔60s检查一次,其大致流程如下:

  • 判断的过期的依据是:当前时间戳 > (上一次发送租约的时间戳 + 过期时间(默认90s) + 补充时间(就是距离上一次执行任务的时间超过定时任务配置的60s执行一次的周期时间));但是由于在设置上一次发送租约的时间戳时候额外加上了一个过期时间;因此最终注册表的过期时间就至少是180s。
  • 选择15%的过期注册信息,然后调用取消操作来删除注册信息;同时会通知集群中其他的节点。

Eureka源码阅读建议

spring-cloud-eureka中的server和client是对netflix的eureka进行了封装,加了一些注解来对spring boot进行支持。因此在阅读eureka源码时,应该先从netflix eureka开始看起,之后再去查看spring cloud封装的eureka的源码就会轻松许多。eureka源码地址:https://github.com/Netflix/eureka 、spring-cloud-eureka源码地址:https://github.com/spring-cloud/spring-cloud-netflix

建议不要直接从github仓库里面去拉取,直接去下载对应版本的压缩包即可。

网上对eureka源码分析的文章有很多,这里推荐2篇写得非常不错的博文:

Eureka原理剖析的更多相关文章

  1. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  2. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

  3. 【Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析】

    原文:[Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析] [注意:]团队里总是有人反映卸载Xamarin,清理不完全.之前写过如何完全卸载清理剩余的文件.今天写了Windows下的批命令 ...

  4. 【Xamarin 跨平台机制原理剖析】

    原文:[Xamarin 跨平台机制原理剖析] [看了请推荐,推荐满100后,将发补丁地址] Xamarin项目从喊口号到现在,好几个年头了,在内地没有火起来,原因无非有三,1.授权费贵 2.贵 3.原 ...

  5. iPhone/Mac Objective-C内存管理教程和原理剖析

    http://www.cocoachina.com/bbs/read.php?tid-15963.html 版权声明 此文版权归作者Vince Yuan (vince.yuan#gmail.com)所 ...

  6. 【Xamain 跨平台机制原理剖析】

    原文:[Xamain 跨平台机制原理剖析] [看了请推荐,推荐满100后,将发补丁地址] Xamarin项目从喊口号到现在,好几个年头了,在内地没有火起来,原因无非有三,1.授权费贵 2.贵 3.原生 ...

  7. Python字符串原理剖析------万恶的+号

    字符串原理剖析pyc文件,执行python代码时,如果导入了其他的.py文件,那么执行过程中会自动生成一个与其同名的.pyc文件,该文件就是python解释器变异之后产生的字节码 PS:代码经过编译可 ...

  8. MapReduce/Hbase进阶提升(原理剖析、实战演练)

    什么是MapReduce? MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算.概念"Map(映射)"和"Reduce(归约)",和他们 ...

  9. ASP.NET Core 运行原理剖析

    1. ASP.NET Core 运行原理剖析 1.1. 概述 1.2. 文件配置 1.2.1. Starup文件配置 Configure ConfigureServices 1.2.2. appset ...

随机推荐

  1. 力扣350. 两个数组的交集 II

    原题 1 class Solution: 2 def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: 3 di ...

  2. Zeebe服务学习1-简单部署与实现demo

    1.Zeebe是什么? Camunda公司研发的工作流引擎Zeebe,目标是对微服务的编排.具体详细介绍可以参考官网:https://zeebe.io/what-is-zeebe/ 2.背景 随着微服 ...

  3. 440. 字典序的第K小数字 + 字典树 + 前缀 + 字典序

    440. 字典序的第K小数字 LeetCode_440 题目描述 方法一:暴力法(必超时) package com.walegarrett.interview; /** * @Author WaleG ...

  4. HDOJ-3065(AC自动机+每个模板串的出现次数)

    病毒侵袭持续中 HDOJ-3065 第一个需要注意的是树节点的个数也就是tree的第一维需要的空间是多少:模板串的个数*最长模板串的长度 一开始我的答案总时WA,原因是我的方法一开始不是这样做的,我是 ...

  5. pytorch(13)卷积层

    卷积层 1. 1d/2d/3d卷积 Dimension of Convolution 卷积运算:卷积核在输入信号(图像)上滑动,相应位置上进行乘加 卷积核:又称为滤波器,过滤器,可认为是某种模式,某种 ...

  6. Java-Socket通信 知识点记录

    目录 一.Socket基本案例 二.消息通信 2.1 双向通信 2.2 告知发送结束 2.2.1 通过Socket关闭 2.2.2 通过Socket关闭输出流的方式 2.2.3 通过约定符号 2.2. ...

  7. EF Core中通过Fluent API完成对表的配置

    EF Core中通过Fluent API完成对表的配置 设置实体在数据库中的表名 通过ToTable可以为数据模型在数据库中自定义表名,如果不配置,则表名为模型名的复数形式 public class ...

  8. JavaScript offset、client、scroll家族

    offsetParent <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  9. java线程实现的三种方式以及静态代理

    线程 一个进程中若开辟多个线程,线程的运行由调度器控制,先后顺序不能人为干预. 实现方式 继承 Thread类 调用run方法,只有主线程一条路 调用start方法,主线程和子线程并行交替执行 pub ...

  10. 涂鸦基于OAuth2在开发者平台上的探索与实践

    前言 开发授权(OAuth2)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资料(如照片.视频.联系人列表),而无需将用户名和密码提供给第三方应用. OAuth2允许用户提供一 ...