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. JavaScript 模拟 sleep

    用 JS 实现沉睡几秒后再执行,有好几种方式,但都不完美,以下是我感觉比较好的一种方式 function sleep(time) { return new Promise((resolve) => ...

  2. 中小企业上云首选,华为云全新云服务器S6性能评测分析

    转: 中小企业上云首选,华为云全新云服务器S6性能评测分析 [小宅按]今天,华为云全新弹性云服务器ECS通用计算型云服务器S6(以下简称为"华为云S6云服务器")正式发布,至顶网云 ...

  3. MySQL使用入门--初识数据库

    MySQL使用入门 数据库概述 数据库是存放数据的仓库.在应用的开发中总是离不开数据的查询.处理.存储,例如图书管理系统就需要操纵和存储大量的数据.没有数据库之前我们使用文件存储数据,但是文件存储有很 ...

  4. 简单的ssm练手联手项目

    简单的ssm练手联手项目 这是一个简单的ssm整合项目 实现了汽车的品牌,价格,车型的添加 ,修改,删除,所有数据从数据库中拿取 使用到了jsp+mysql+Mybatis+spring+spring ...

  5. 如何自己配置pip源

    方式一:临时使用国内pypi镜像安装 pip install -i http://pypi.douban.com/simple/ numpy pip install -i http://pypi.do ...

  6. Tornado 简明教程

    1.TornadoTornado:python编写的web服务器兼web应用框架1.1.Tornado的优势轻量级web框架异步非阻塞IO处理方式出色的抗负载能力优异的处理性能,不依赖多进程/多线程, ...

  7. python学习8 文件的操作

    本文拷贝了on testing 的<python之文件操作:文件的读写>,只做学习之用 python的文件读写通过 一.用open函数 二.对文件读写操作 三.读取文件位置定位 1. op ...

  8. DAOS 分布式异步对象存储|事务模型

    DAOS API 支持分布式事务,允许将针对属于同一 Container 的对象的任何更新操作组合到单个 ACID 事务中.分布式一致性是通过基于多版本时间戳排序的无锁乐观并发控制机制提供的.DAOS ...

  9. 一文教你搞懂 Go 中栈操作

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/513 本文使用的go的源码15.7 知识点 LInux 进程在内存布 ...

  10. 快速了解Web MVC设计模式

    MVC概述 MVC即 Model-View-Controller 的缩写,是按照职责划分模块一种设计模式,其中Model是核心. Model:模型.负责执行实际的业务,包含数据操作,可以向视图推送数据 ...