微服务注册后,在注册中心的注册表结构是一个map: ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry,假如一个order服务部署了三台机器,那么Map的第一个key为服务名称,第二个map的key是实例编号(instance-id),

InstanceInfo该对象封装了服务的主要信息,例如ip 端口 服务名称 服务的编号等:

如图:

一、服务的注册

1.客户端源码(DiscoveryClient类里面):

2.服务端的源码(AbstractInstanceRegistry类):

二、服务的续约

1.客户端源码(DiscoveryClient类里面):通过发送心跳进行续约,告诉注册中心我还活着

  

2.服务端的源码(AbstractInstanceRegistry类):

三、服务的下线(客户端关闭时,主动发送消息给注册中心,注册中心从注册表中将该服务实例删除)

1.客户端源码(DiscoveryClient类里面):

  

  

2.服务端的源码(AbstractInstanceRegistry类):

四、服务的剔除:当注册中心服务器一直收不到客户端的心跳续约超过一定时间限制时,注册中心会将该服务从注册表中剔除,该功能只存在注册中心

注册中心源码(AbstractInstanceRegistry类):

五、服务的发现:客户端要向注册中心拉取注册列表

1.客户端源码(DiscoveryClient类里面):

1.1全量拉取:

1.2 增量拉取

2.服务端的源码(AbstractInstanceRegistry类):

2.1 注册中心全量拉取:

2.2 增量拉取:

六 、定时器

1.客户端会定时向注册中心发送心跳进行续约以及定时去注册中心拉取最新的注册列表信息

客户端源码(DiscoveryClient类的构造器里):省略部分无关代代码:

@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider, EndpointRandomizer endpointRandomizer) {
//此处省略了部分代码
try {
//创建一个线程调度器
scheduler = Executors.newScheduledThreadPool(2,
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-%d")
.setDaemon(true)
.build());
//处理心跳的线程池
heartbeatExecutor = new ThreadPoolExecutor(
1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
//拉取注册表的线程池
cacheRefreshExecutor = new ThreadPoolExecutor(
1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff //此处省略部分无关代码
initScheduledTasks(); //调用该方法,该方法会执行对应的线程池 }
  */
private void initScheduledTasks() {
if (clientConfig.shouldFetchRegistry()) {
// registry cache refresh timer
int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
cacheRefreshTask = new TimedSupervisorTask(
"cacheRefresh",
scheduler,
cacheRefreshExecutor,
registryFetchIntervalSeconds,
TimeUnit.SECONDS,
expBackOffBound,
new DiscoveryClient.CacheRefreshThread() //该方法里面会调用拉取注册表的方法
);
scheduler.schedule(
cacheRefreshTask,
registryFetchIntervalSeconds, TimeUnit.SECONDS); //开启定时任务
} if (clientConfig.shouldRegisterWithEureka()) {
int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs); // Heartbeat timer
heartbeatTask = new TimedSupervisorTask(
"heartbeat",
scheduler,
heartbeatExecutor,
renewalIntervalInSecs,
TimeUnit.SECONDS,
expBackOffBound,
new HeartbeatThread();//该线程会去调用发送心跳方法
);
scheduler.schedule(
heartbeatTask,
renewalIntervalInSecs, TimeUnit.SECONDS); //开启心跳定时任务
//此处省略部分无关代码
}

//拉取注册列表的线程:

//发送心跳的线程:

2. 注册中心服务剔除定时器(注册中心源码(AbstractInstanceRegistry类))

总结:eureka注册中心是去化的,注册表是存在内存中的,并且客户端拉取一份注册表后,会存在本地缓存中,因此即使注册中心挂了,一样不影响客户端相互调用

附加: 客户端如何获取服务实例demo

综上所述,其实我们也可以自己写个简单的注册中心,思路如下:

1.创建一个springboot项目,写个controller类,提供注册,续约,下线,获取服务列表四个接口

2. 定义一个实例对象Instance,该对象封装ip,端口 还有更新时间

3.客户端调用注册接口,将Instance作为参数传过来,注册中心取到对应实例,存到Map<String,Map<String,Instance>> 中

4.客户端弄个定时器,每个一段时间,调用注册中心的续约方法,将更新实例的修改时间

5.客户端弄个定时器,每隔一段时间向注册中心拉取服务,其实就是拉取Map<String,Map<String,Instance>>

6.注册中心弄个定时器,每隔一段时间遍历Map<String,Map<String,Instance>>,找出每个实例中的更新时间,加上过期时间,然后跟当前时间比较,看看有没过期,如果过期就剔除,也就是在map中删除

												

eureka源码--服务的注册、服务续约、服务发现、服务下线、服务剔除、定时任务以及自定义注册中心的思路的更多相关文章

  1. Spring Cloud Eureka源码分析之服务注册的流程与数据存储设计!

    Spring Cloud是一个生态,它提供了一套标准,这套标准可以通过不同的组件来实现,其中就包含服务注册/发现.熔断.负载均衡等,在spring-cloud-common这个包中,org.sprin ...

  2. 【SpringCloud Eureka源码】从Eureka Client发起注册请求到Eureka Server处理的整个服务注册过程(下)

    目录 一.Spring Cloud Eureka Server自动配置及初始化 @EnableEurekaServer EurekaServerAutoConfiguration - 注册服务自动配置 ...

  3. 【一起学源码-微服务】Nexflix Eureka 源码六:在眼花缭乱的代码中,EurekaClient是如何注册的?

    前言 上一讲已经讲解了EurekaClient的启动流程,到了这里已经有6篇Eureka源码分析的文章了,看了下之前的文章,感觉代码成分太多,会影响阅读,后面会只截取主要的代码,加上注释讲解. 这一讲 ...

  4. 微服务之SpringCloud实战(四):SpringCloud Eureka源码分析

    Eureka源码解析: 搭建Eureka服务的时候,我们会再SpringBoot启动类加上@EnableEurekaServer的注解,这个注解做了一些什么,我们一起来看. 点进@EnableEure ...

  5. 【一起学源码-微服务】Nexflix Eureka 源码十:服务下线及实例摘除,一个client下线到底多久才会被其他实例感知?

    前言 前情回顾 上一讲我们讲了 client端向server端发送心跳检查,也是默认每30钟发送一次,server端接收后会更新注册表的一个时间戳属性,然后一次心跳(续约)也就完成了. 本讲目录 这一 ...

  6. 【一起学源码-微服务】Nexflix Eureka 源码十一:EurekaServer自我保护机制竟然有这么多Bug?

    前言 前情回顾 上一讲主要讲了服务下线,已经注册中心自动感知宕机的服务. 其实上一讲已经包含了很多EurekaServer自我保护的代码,其中还发现了1.7.x(1.9.x)包含的一些bug,但这些问 ...

  7. 【一起学源码-微服务】Nexflix Eureka 源码十二:EurekaServer集群模式源码分析

    前言 前情回顾 上一讲看了Eureka 注册中心的自我保护机制,以及里面提到的bug问题. 哈哈 转眼间都2020年了,这个系列的文章从12.17 一直写到现在,也是不容易哈,每天持续不断学习,输出博 ...

  8. 【一起学源码-微服务】Nexflix Eureka 源码十三:Eureka源码解读完结撒花篇~!

    前言 想说的话 [一起学源码-微服务-Netflix Eureka]专栏到这里就已经全部结束了. 实话实说,从最开始Eureka Server和Eureka Client初始化的流程还是一脸闷逼,到现 ...

  9. 【一起学源码-微服务】Nexflix Eureka 源码二:EurekaServer启动之配置文件加载以及面向接口的配置项读取

    前言 上篇文章已经介绍了 为何要读netflix eureka源码了,这里就不再概述,下面开始正式源码解读的内容. 如若转载 请标明来源:一枝花算不算浪漫 代码总览 还记得上文中,我们通过web.xm ...

随机推荐

  1. 使用PowerShell连接Ubuntu

    Ubuntu安装PowerShell Ubuntu安装PowerShell帮助文档 # Download the Microsoft repository GPG keys wget -q https ...

  2. vimrc备份

    备份一下我的 gvim 配置文件 " 使vimrc文件立马生效 autocmd BufWritePost $MYVIMRC source $MYVIMRC " 设置自己的Leade ...

  3. 4gl游标cursor

    游標有多種寫法,一種是報表里常見的 這種寫法呢,先定義一個接受sql語句的變量l_sql,而接受到的語句實際上只是一連串的字符串,還包含了4gl裡面的一些變量.寫好的l_sql裡面之所以有多個分段的雙 ...

  4. CODING DevOps 代码质量实战系列第二课: PHP 版

    讲师介绍 杨周 CODING DevOps 架构师 CODING 布道师 连续创业者.DIY/Linux 玩家.知乎小 V,曾在创新工场.百度担任后端开发.十余年一线研发和带队经验,经历了 ToB.T ...

  5. JS学习阶段性总结-1

    各种函数的声明 /** * 函数的声明 */ // 声明一个方法,任意调用 function aaa(args){...} // 声明一个函数并以变量的形式展示出去,因此无法再声明前调用 var fn ...

  6. 断言函数-RF

    测试用例的目的是要验证一些操作否符合我们的预期结果,所以在测试用例中,断言函数是必不可少的一项.我们做的每一步操作都会有预期的结果,为了保证操作得到的结果符合预期,我们需要在测试用例中添加断言,来保证 ...

  7. 力扣Leetcode 55. 跳跃游戏

    跳跃游戏 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4] 输出: ...

  8. 前端防止xxs注入

    思路:        去掉所有跟sql有关的标签: $(function () { $(":input").change(function () { // alert($(this ...

  9. Android开发之去掉listview的点击效果,一行代码间接粗暴,解决你的问题。

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 Android开发之去掉listview的点击效果,一行代码间接粗暴,解决你的问题. 当你在用list ...

  10. Android开发java程序员常用代码,将字符串以逗号分别取出字符串String

    public class StringSplit { public static void main(String[] args) { String sourceStr = "1,2,3,4 ...