【深入理解SpringCloud微服务】深入理解Eureka核心原理

news2024/11/15 4:20:13

深入理解Eureka核心原理

  • Eureka整体设计
  • Eureka服务端启动
  • Eureka三级缓存
  • Eureka客户端启动

Eureka整体设计

Eureka是一个经典的注册中心,通过http接收客户端的服务发现和服务注册请求,使用内存注册表保存客户端注册上来的实例信息。

Eureka服务端接收的是http请求,通过ApplicationResource接收服务注册请求,通过ApplicationsResource接收服务发现请求,这两个类相当于Spring MVC中的Controller,Eureka使用的不是Spring MVC,而是Jersey,我们直接把他们当成Controller即可。

然后Eureka用一个内存实例注册表PeerAwareInstanceRegistry保存服务提供者注册上来的实例信息,当ApplicationResource接收到服务注册请求时,会把服务实例信息存入PeerAwareInstanceRegistry;当ApplicationsResource接收到服务发现请求时,会从PeerAwareInstanceRegistry拉取服务实例信息返回给客户端

在这里插入图片描述

public class ApplicationsResource {

	private final PeerAwareInstanceRegistry registry;

	...
}
public class ApplicationResource {

	private final PeerAwareInstanceRegistry registry;

	...
}

Eureka服务端启动

Eureka服务端启动时会初始化PeerAwareInstanceRegistry接口的实现类以及其他核心类,除了初始化PeerAwareInstanceRegistry等一些核心类之外,还会做两件事:

  1. 从集群中的其他Eureka拉取服务实例列表,注册到自己本地的服务注册表
  2. 开启服务剔除定时任务,定时扫描超过一定期限没有续约的服务实例,把它剔除出内存注册表

在这里插入图片描述

初始化PeerAwareInstanceRegistry的代码在EurekaServerAutoConfiguration中,通过@Bean往Spring容器注册一个InstanceRegistry对象,这个InstanceRegistry就是peerAwareInstanceRegistry的实现类。

	@Bean
	public PeerAwareInstanceRegistry peerAwareInstanceRegistry(
			ServerCodecs serverCodecs) {
		...
		return new InstanceRegistry(...);
	}

EurekaServerAutoConfiguration还会通过@Import注解导入一个EurekaServerInitializerConfiguration,这个EurekaServerInitializerConfiguration的start()方法会触发集群同步和启动服务剔除定时任务。

	@Override
	public void start() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					// EurekaServerAutoConfiguration导入的EurekaServerBootstrap
					// 启动Eureka服务
					eurekaServerBootstrap.contextInitialized(
							EurekaServerInitializerConfiguration.this.servletContext);
					...
				}
				catch (...) {...}
			}
		}).start();
	}
	public void contextInitialized(ServletContext context) {
		try {
			//初始化Eureka运行环境
			initEurekaEnvironment();
			//初始化Eureka服务上下文
			initEurekaServerContext();

			...
		}
		catch (...) {...}
	}

重点是initEurekaServerContext()方法:

protected void initEurekaServerContext() throws Exception {
		...
		
		// 集群同步(从集群中的其他Eureka实例拉取服务实例列表)
		int registryCount = this.registry.syncUp();
		// 启动服务提测定时任务
		this.registry.openForTraffic(this.applicationInfoManager, registryCount);

		...
	}

Eureka三级缓存

Eureka处理服务发现请求时,其实并不是直接读取内存注册表的,而是读的缓存。Eureka除了内存注册表以外,还有两个缓存,一个是读写缓存readWriteCacheMap,一个是只读缓存readOnlyCacheMap。内存注册表、readWriteCacheMap、readOnlyCacheMap三个组成了Eureka的三级缓存。其中readWriteCacheMap和readOnlyCacheMap被包装在一个ResponseCache对象中。整个三级缓存的结果就是这样:

在这里插入图片描述

public class PeerAwareInstanceRegistryImpl extends AbstractInstanceRegistry implements PeerAwareInstanceRegistry {
	...
}
public abstract class AbstractInstanceRegistry implements InstanceRegistry {
    ...
    protected volatile ResponseCache responseCache;
    ...

当ApplicationsResource接收到服务发现请求时:

  1. 先从只读缓存中取
  2. 如果只读缓存中没有,则从读写缓存获取并且回写只读缓存
  3. 如果读写缓存中也没有,则从内存注册表中获取并回写到读写缓存。

Eureka会开启一个定时任务,每隔30s从读写缓存同步数据到只读缓存。

在这里插入图片描述

ResponseCacheImpl#getValue:

    Value getValue(final Key key, boolean useReadOnlyCache) {
        Value payload = null;
        try {
            if (useReadOnlyCache) {
            	// 从只读缓存取
                final Value currentPayload = readOnlyCacheMap.get(key);
                if (currentPayload != null) {
                    payload = currentPayload;
                } else {
                	// 只读缓存没有,则从读写缓存取,回写只读缓存
                    payload = readWriteCacheMap.get(key);
                    readOnlyCacheMap.put(key, payload);
                }
            } else {
                payload = readWriteCacheMap.get(key);
            }
        } catch (...) {...}
        return payload;
    }

readWriteCacheMap的类型是LoadingCache,LoadingCache是Guava库提供的一个本地缓存实现。当LoadingCache缓存缺失时,LoadingCache会触发CacheLoader的load方法,加载数据到缓存中,此时就会从内存注册表中加载数据到readWriteCacheMap中。关于LoadingCache的使用、作用、原理等知识,可以参考讲解Guava缓存相关的资料。

当ApplicationResource接收到服务注册请求时,会把服务实例信息写入内存注册表,并失效掉读写缓存,然后把新注册上来的实例信息异步同步到集群中的其他Eureka节点。

在这里插入图片描述

PeerAwareInstanceRegistryImpl#register

    @Override
    public void register(final InstanceInfo info, final boolean isReplication) {
        ...
        super.register(info, leaseDuration, isReplication);
        // 同步到集群中的其他Eureka节点
        replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
    }

AbstractInstanceRegistry#register:

    public void register(InstanceInfo registrant, ...) {
        try {
            ...
            // 失效读写缓存
            invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
            ...
        } finally {
            ...
        }
    }

    private void invalidateCache(String appName, @Nullable String vipAddress, @Nullable String secureVipAddress) {
        // invalidate cache
        responseCache.invalidate(appName, vipAddress, secureVipAddress);
    }

Eureka客户端启动

Eureka的客户端启动时会创建一个DiscoveryClient对象,它是Eureka的客户端对象,它会创建两个定时任务,一个异步延时任务。

两个定时任务:

  1. 定时拉取服务实例列表(服务发现
  2. 定时发送心跳(服务续约

一个延时任务:服务注册

DiscoveryClient的构造方法:

    @Inject
    DiscoveryClient(...) {
        ...
        initScheduledTasks();
        ...
    }

DiscoveryClient#initScheduledTasks

    private void initScheduledTasks() {
        if (clientConfig.shouldFetchRegistry()) {
            ...
            // 开启服务发现定时任务
            scheduler.schedule(
                    new TimedSupervisorTask(
                            ...
                            new CacheRefreshThread()
                    ),
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }

        if (clientConfig.shouldRegisterWithEureka()) {
            ...
            // 开启服务续约(定时发送心跳)定时任务
            scheduler.schedule(
                    new TimedSupervisorTask(
                    		...
                            new HeartbeatThread()
                    ),
                    renewalIntervalInSecs, TimeUnit.SECONDS);

            
            instanceInfoReplicator = new InstanceInfoReplicator(...);
            ...
			// 服务注册
            instanceInfoReplicator.start(...);
        } else {...}
    }

它们都是通过Jersey客户端向Eureka服务端发起http请求。

其中服务发现的定时任务在首次拉取是会全量拉取,后续会进行增量拉取。增量拉取返回的服务实例列表会合并到Eureka客户端的本地缓存中,然后根据本地缓存的服务实例列表计算一个hashCode,与Eureka服务端返回的hashCode进行比较,如果不一致,还要再进行一次全量拉取。

在这里插入图片描述

以上就是Eureka全部的核心原理,下面放一张源码图,对源码有兴趣的可以跟一跟,没有兴趣的可以直接忽略。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1942795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQLite读取分析指南:新手也能轻松上手的实用教程

SQLite是一个轻量级的关系型数据库,目前已经更新到SQLite3版本。它不仅具有跨平台的特性而且占用的资源非常低,目标是设计来做嵌入式的。本教程将深入浅出地讲解图形化界面和python脚本来读取sqlite数据库这两种方法,从基础概念到实际应用,step by step地…

Windows定时任务实现关闭和开启声音

目录 1. 下载并放置 nircmd.exe1.1 下载 NirCmd:1.2 放置 nircmd.exe: 2. 定时关闭声音2.1 打开任务计划程序:2.2 创建基本任务:2.3 设置任务名称和描述:2.4 触发器:2.5 操作:2.6 设置程序或脚本…

新手小白的pytorch学习第十弹----多类别分类问题模型以及九、十弹的练习

目录 1 多类别分类模型1.1 创建数据1.2 创建模型1.3 模型传出的数据1.4 损失函数和优化器1.5 训练和测试1.6 衡量模型性能的指标 2 练习Exercise 之前我们已经学习了 二分类问题,二分类就像抛硬币正面和反面,只有两种情况。 这里我们要探讨一个 多类别…

专业护眼灯品牌有哪些?五款爆款护眼灯品牌推荐

在当今时代,电子设备在我们的日常生活中扮演着越来越重要的角色。然而,长时间使用这些设备可能会增加眼睛疲劳和近视的风险。为了解决这一问题,护眼台灯应运而生,并逐渐成为许多家庭和办公室的必需品。面对市场上琳琅满目的护眼台…

<数据集>苹果腐烂识别数据集<目标检测>

数据集格式:VOCYOLO格式 图片数量:978张 标注数量(xml文件个数):978 标注数量(txt文件个数):978 标注类别数:2 标注类别名称:[fresh_apple, rotten_apple] 序号类别名称图片数框数1fresh_apple520922…

排序算法与复杂度介绍

1. 排序算法 1.1 排序算法介绍 排序也成排序算法(Sort Algorithm),排序是将一组数据,依照指定的顺序进行排序的过程 1.2 排序的分类 1、内部排序: 指将需要处理的所有数据都加载到**内部存储器(内存&am…

【NLP自然语言处理】基于BERT实现文本情感分类

Bert概述 BERT(Bidirectional Encoder Representations from Transformers)是一种深度学习模型,用于自然语言处理(NLP)任务。BERT的核心是由一种强大的神经网络架构——Transformer驱动的。这种架构包含了一种称为自注…

MySQL_JDBC

目录 一、JDBC常用的接口和类 1.1 数据库连接 Connection 1.2 Statement 对象 二、JDBC的使用 总结 【Java 的数据库编程】 JDBC 即 Java Database Connectivity (Java数据库连接),是一种用于执行 SQL 语句的 Java API。这个 API 由 java.sql.*,javax.sql.* …

零基础学SpringBoot(一)--初识SpringBoot

1. SpringBoot简介 SpringBoot 是Spring家族中的一个全新的框架,它用来简化Spring应用程序的创建和开发过程,也可以说Spring Boot能简化我们之前采用SSM(SpringMVC Spring MyBatis)框架进行开发的过程。 以前我们采用SSM框架进行开发的时候&#xff0c…

算法017:二分查找

二分查找. - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/binary-search/ 二分查找,其实是双指针的一种特殊情况,但是时间复杂度极低&#…

python的csv库常用操作

csv 模块是 Python 标准库中的一个模块,用于处理 CSV(逗号分隔值)文件。它提供了简单易用的功能来读取和写入 CSV 文件。以下是一些常用的操作: 一、读取 CSV 文件 新建文件data.csv,内容如下: 使用 csv.…

使用JAVA代码实现生成二维码

系列文章目录 1.SpringBoot整合RabbitMQ并实现消息发送与接收 2. 解析JSON格式参数 & 修改对象的key 3. VUE整合Echarts实现简单的数据可视化 4. List<HashMap<String,String>>实现自定义字符串排序(key排序、Val…

录屏神器!这四款软件让你轻松记录屏幕

随着现在在线教育的兴起,用录屏软件将课程录制下来能够帮助我助我们通过视频分享知识,展示成果。电脑怎么录屏的重要性愈发凸显了,下面我为你介绍几款热门的 录屏软件吧。 1.福晰REC大师 这个软件是我用过觉得最顺手的一款了。它录制的视频…

c++ 高精度加法(只支持正整数)

再给大家带来一篇高精度,不过这次是高精度加法!话不多说,开整! 声明 与之前那篇文章一样,如果看起来费劲可以结合总代码来看 定义 由于加法进位最多进1位,所以我们的结果ans[]的长度定义为两个加数中最…

马斯克:xAI启动“最强大AI训练集群” 年底推出全球最强AI

埃隆马斯克最近在社交平台上表示,xAI已经启动了“世界上最强大的 AI 集群”,以在今年12 月之前创建“世界上最强大的AI”。马斯克自豪地透露,得益于xAI团队、X团队、Nvidia及众多合作伙伴的紧密协作,位于孟菲斯的超级计算工厂“Su…

【BUG】已解决:libpng warning: iccp: known incorrect sRGB profile

已解决:libpng warning: iccp: known incorrect sRGB profile 目录 已解决:libpng warning: iccp: known incorrect sRGB profile 【常见模块错误】 错误原因: 原因分析 解决方案 具体步骤 欢迎来到英杰社区https://bbs.csdn.net/topics…

请你谈谈:spring bean的生命周期 - 阶段4:检查Aware相关接口

在Spring框架中,Aware 接口系列提供了一种机制,允许bean在初始化过程中感知到容器中的特定对象,如应用上下文(ApplicationContext)、Bean工厂(BeanFactory)等。如果你有一个用户自定义的对象&am…

ReLU-KAN:仅需要矩阵加法、点乘和ReLU*的新型Kolmogorov-Arnold网络

摘要 由于基函数(B样条)计算的复杂性,Kolmogorov-Arnold网络(KAN)在GPU上的并行计算能力受到限制。本文提出了一种新的ReLU-KAN实现方法,该方法继承了KAN的核心思想。通过采用ReLU(修正线性单元…

计算机视觉与面部识别:技术、应用与未来发展

引言 在当今数字化时代,计算机视觉技术迅速发展,成为人工智能领域的一个重要分支。计算机视觉旨在让机器理解和解释视觉信息,模拟人类的视觉系统。它在各行各业中发挥着重要作用,从自动驾驶汽车到智能监控系统,再到医疗…

2 fabric 关键概念

Peer 节点 区块链网络主要由 Peer 节点(或者简单称之为 Peer)组成。Peer 是网络的基本元素,因为他们存储了账本和智能合约。之前我们说过账本不可篡改地保存着智能合约生成的所有交易(在 Hyperledger Fabric 中智能合约包含在链码中,稍后会详细介绍)。智能合约和账本将网…