> 文档中心 > 彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka

彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka

文接上回,咱们继续聊聊Spring Cloud相关的知识,希望大家能有所收获!

咱们先讲Eureka哈

在这里插入图片描述

Eureka服务注册中⼼

关于服务注册中⼼

注意:服务注册中⼼本质上是为了解耦服务提供者和服务消费者。

对于任何⼀个微服务,原则上都应存在或者⽀持多个提供者(⽐如订单微服务部署多个实例),这是由微服务的分布式属性决定的。

更进⼀步,为了⽀持弹性扩缩容特性,⼀个微服务的提供者的数量和分布往往是动态变化的,也是⽆法预先确定的。因此,原本在单体应⽤阶段常⽤的静态LB机制就不再适⽤了,需要引⼊额外的组件来管理微服务提供者的注册与发现,⽽这个组件就是服务注册中⼼。

服务注册中⼼⼀般原理

在这里插入图片描述
分布式微服务架构中,服务注册中⼼⽤于存储服务提供者地址信息、服务发布相关的属性信息,消费者通过主动查询和被动通知的⽅式获取服务提供者的地址信息,⽽不再需要通过硬编码⽅式得到提供者的地址信息。消费者只需要知道当前系统发布了那些服务,⽽不需要知道服务具体存在于什么位置,这就是透明化路由。

  1. 服务提供者启动
  2. 服务提供者将相关服务信息主动注册到注册中⼼
  3. 服务消费者获取服务注册信息:
    • poll模式:服务消费者可以主动拉取可⽤的服务提供者清单
    • push模式:服务消费者订阅服务(当服务提供者有变化时,注册中⼼也会主动推送更新后的服务清单给消费者
  4. 服务消费者直接调⽤服务提供者

另外,注册中⼼也需要完成服务提供者的健康监控,当发现服务提供者失效时需要及时剔除;

主流服务中⼼对⽐
  • Zookeeper
    Zookeeper它是⼀个分布式服务框架,是Apache Hadoop 的⼀个⼦项⽬,它主要是⽤来解决分布式应 ⽤中经常遇到的⼀些数据管理问题,如:统⼀命名服务、状态同步服务、集群管理、分布式应⽤配置项的管理等。
    简单来说zookeeper本质=存储+监听通知
    znode
    Zookeeper ⽤来做服务注册中⼼,主要是因为它具有节点变更通知功能,只要客户端监听相关服务节点,服务节点的所有变更,都能及时的通知到监听客户端,这样作为调⽤⽅只要使⽤Zookeeper 的客户端就能实现服务节点的订阅和变更通知功能了,⾮常⽅便。另外,Zookeeper可⽤性也可以,因为只要半数以上的选举节点存活,整个集群就是可⽤的。
  • Eureka
    由Netflix开源,并被Pivatal集成到SpringCloud体系中,它是基于 RestfulAPI ⻛格开发的服务注册与发现组件。
  • Consul
    Consul是由HashiCorp基于Go语⾔开发的⽀持多数据中⼼分布式⾼可⽤的服务发布和注册服务软件, 采⽤Raft算法保证服务的⼀致性,且⽀持健康检查。
  • Nacos
    Nacos是⼀个更易于构建云原⽣应⽤的动态服务发现、配置管理和服务管理平台。简单来说 Nacos就是 注册中⼼ + 配置中⼼的组合,帮助我们解决微服务开发必会涉及到的服务注册 与发现,服务配置,服务管理等问题。Nacos 是 Spring Cloud Alibaba 核⼼组件之⼀,负责服务注册与发现,还有配置。

表格对比

组件名 语⾔ CAP 对外暴露接⼝
Eureka Java AP(⾃我保护机制,保证可⽤) HTTP
Consul Go CP HTTP/DNS
Zookeeper Java CP 客户端
Nacos Java ⽀持AP/CP切换 HTTP

既然有CAP,那大家还记得这篇《分布式理论》吗?先简单回顾下,细节大家回过头去研究哈

  • P:分区容错性(⼀定的要满⾜的)
  • C:数据⼀致性
  • A:⾼可⽤
    CAP不可能同时满⾜三个,要么是AP,要么是CP

服务注册中⼼组件 Eureka

服务注册中⼼的⼀般原理、对⽐了主流的服务注册中⼼⽅案
⽬光聚焦Eureka

  • Eureka 基础架构
    在这里插入图片描述

  • Eureka 交互流程及原理
    下图是官⽹描述的⼀个架构图
    在这里插入图片描述
    Eureka 包含两个组件:Eureka Server 和 Eureka Client,Eureka Client是⼀个Java客户端,⽤于简化与Eureka Server的交互;Eureka Server提供服务发现的能⼒,各个微服务启动时,会通过Eureka Client向Eureka Server 进⾏注册⾃⼰的信息(例如⽹络信息),Eureka Server会存储该服务的信息;

  1. 图中us-east-1c、us-east-1d,us-east-1e代表不同的区也就是不同的机房
  2. 图中每⼀个Eureka Server都是⼀个集群。
  3. 图中Application Service作为服务提供者向Eureka Server中注册服务,Eureka Server接受到注册事件会在集群和分区中进⾏数据同步,Application Client作为消费端(服务消费者)可以从Eureka Server中获取到服务注册信息,进⾏服务调⽤。
  4. 微服务启动后,会周期性地向Eureka Server发送⼼跳(默认周期为30秒)以续约⾃⼰的信息
  5. Eureka Server在⼀定时间内没有接收到某个微服务节点的⼼跳,Eureka Server将会注销该微服务节点(默认90秒)
  6. 每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的⽅式完成服务注册列表的同步
  7. Eureka Client会缓存Eureka Server中的信息。即使所有的Eureka Server节点都宕掉,服务消费者依然可以使⽤缓存中的信息找到服务提供者

Eureka通过⼼跳检测、健康检查和客户端缓存等机制,提⾼系统的灵活性、可伸缩性和可⽤性。

EurekaServer图解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Eureka细节详解

Eureka元数据详解

Eureka的元数据有两种:标准元数据和⾃定义元数据

  • 标准元数据:主机名、IP地址、端⼝号等信息,这些信息都会被发布在服务注册表中,⽤于服务之间的调⽤。
  • ⾃定义元数据:可以使⽤eureka.instance.metadata-map配置,符合KEY/VALUE的存储格式。这 些元数据可以在远程客户端中访问。

类似于

instance: prefer-ip-address: true metadata-map:# ⾃定义元数据(kv⾃定义)cluster: cl1 region: rn1

我们可以在程序中可以使⽤DiscoveryClient 获取指定微服务的所有元数据信息

import com.learn.edu.AutodeliverApplication;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;import java.util.Map;@SpringBootTest(classes = {AutodeliverApplication.class})@RunWith(SpringJUnit4ClassRunner.class)public class AutodeliverApplicationTest {@Autowiredprivate DiscoveryClient discoveryClient;@Testpublic void test() {// 从EurekaServer获取指定微服务实例List<ServiceInstance> serviceInstanceList = discoveryClient.getInstances("learn-service-resume");// 循环打印每个微服务实例的元数据信息for (int i = 0; i < serviceInstanceList.size(); i++) {ServiceInstance serviceInstance = serviceInstanceList.get(i);System.out.println(serviceInstance); } }}

元数据查看如下
在这里插入图片描述
在这里插入图片描述

Eureka客户端详解

服务提供者(也是Eureka客户端)要向EurekaServer注册服务,并完成服务续约等⼯作
服务注册详解(服务提供者)

  1. 当我们导⼊了eureka-client依赖坐标,配置Eureka服务注册中⼼地址
  2. 服务在启动时会向注册中⼼发起注册请求,携带服务元数据信息
  3. Eureka注册中⼼会把服务的信息保存在Map中。
  • 服务续约详解(服务提供者)
    服务每隔30秒会向注册中⼼续约(⼼跳)⼀次(也称为报活),如果没有续约,租约在90秒后到期,然后服务会被失效。每隔30秒的续约操作我们称之为⼼跳检测

    往往不需要我们调整这两个配置

    #向Eureka服务中⼼集群注册服务eureka: instance:# 租约续约间隔时间,默认30秒 lease-renewal-interval-in-seconds: 30# 租约到期,服务时效时间,默认值90秒,服务超过90秒没有发⽣⼼跳,EurekaServer会将服务从列表移除 lease-expiration-duration-in-seconds: 90
  • 获取服务列表详解(服务消费者)
    每隔30秒服务会从注册中⼼中拉取⼀份服务列表,这个时间可以通过配置修改。
    往往不需要我们调整

    #向Eureka服务中⼼集群注册服务eureka:  client:# 每隔多久拉取⼀次服务列表 registry-fetch-interval-seconds: 30
    • 服务消费者启动时,从 EurekaServer服务列表获取只读备份,缓存到本地
    • 每隔30秒,会重新获取并更新数据
    • 每隔30秒的时间可以通过配置eureka.client.registry-fetch-interval-seconds修改
Eureka服务端详解
  • 服务下线

    • 当服务正常关闭操作时,会发送服务下线的REST请求给EurekaServer。
    • 服务中⼼接受到请求后,将该服务置为下线状态
  • 失效剔除
    Eureka Server会定时(间隔值是eureka.server.eviction-interval-timer-in-ms,默认60s)进⾏检查,如果发现实例在在⼀定时间(此值由客户端设置的eureka.instance.lease-expiration-duration-inseconds定义,默认值为90s)内没有收到⼼跳,则会注销此实例。

  • ⾃我保护
    服务提供者 —> 注册中⼼
    定期的续约(服务提供者和注册中⼼通信),假如服务提供者和注册中⼼之间的⽹络有点问题,不代表服务提供者不可⽤,不代表服务消费者⽆法访问服务提供者

    如果在15分钟内超过85%的客户端节点都没有正常的⼼跳,那么Eureka就认为客户端与注册中⼼出现了⽹络故障,Eureka Server⾃动进⼊⾃我保护机制。

    为什么会有⾃我保护机制?

    默认情况下,如果Eureka Server在⼀定时间内(默认90秒)没有接收到某个微服务实例的⼼跳,Eureka Server将会移除该实例。但是当⽹络分区故障发⽣时,微服务与Eureka Server之间⽆法正常通信,⽽微服务本身是正常运⾏的,此时不应该移除这个微服务,所以引⼊了⾃我保护机制。

    服务中⼼⻚⾯会显示如下提示信息
    彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
    当处于⾃我保护模式时

    • 不会剔除任何服务实例(可能是服务提供者和EurekaServer之间⽹络问题),保证了⼤多数服务依然可⽤
  • Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可⽤,当⽹络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

  • 在Eureka Server⼯程中通过eureka.server.enable-self-preservation配置可⽤关停⾃我保护,默认值是打开

    eureka: server:    enable-self-preservation: false # 关闭⾃我保护模式(缺省为打开)

经验:建议⽣产环境打开⾃我保护机制

Eureka核⼼源码剖析

Eureka Server启动过程

⼊⼝:SpringCloud充分利⽤了SpringBoot的⾃动装配的特点

  • 观察eureka-server的jar包,发现在META-INF下⾯有配置⽂件spring.factories
    在这里插入图片描述

springboot应⽤启动时会加载EurekaServerAutoConfiguration⾃动配置类

  • EurekaServerAutoConfiguration类
    ⾸先观察类头分析
    在这里插入图片描述
    上图中的(1)需要有⼀个marker bean,才能装配Eureka Server,那么这个marker 其实是由@EnableEurekaServer注解决定的
    在这里插入图片描述
    在这里插入图片描述
    也就是说只有添加了@EnableEurekaServer注解,才会有后续的动作,这是成为⼀个EurekaServer的前提

    图中的(2)关注EurekaServerAutoConfiguration
    彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka

    在这里插入图片描述
    在这里插入图片描述
    ⽽在 com.netflix.eureka.cluster.PeerEurekaNodes#start⽅法中
    在这里插入图片描述

    回到主配置类中
    在这里插入图片描述
    在这里插入图片描述
    回到主配置类中
    在这里插入图片描述
    在这里插入图片描述
    图中的(3)关注EurekaServerInitializerConfiguration
    在这里插入图片描述
    在这里插入图片描述
    重点关注,进⼊org.springframework.cloud.netflix.eureka.server.EurekaServerBootstrap#contextInitialized
    在这里插入图片描述
    重点关注initEurekaServerContext()
    在这里插入图片描述
    研究⼀下上图中的syncUp⽅法
    在这里插入图片描述
    继续研究com.netflix.eureka.registry.AbstractInstanceRegistry#register(提供实例注册功能)
    在这里插入图片描述
    继续研究com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#openForTraffic
    在这里插入图片描述
    进⼊postInit()⽅法查看
    在这里插入图片描述

Eureka Server服务接⼝暴露策略

在Eureka Server启动过程中主配置类注册了Jersey框架(是⼀个发布restful⻛格接⼝的框架,类似于我们的springmvc)
在这里插入图片描述
注⼊的Jersey细节
在这里插入图片描述
扫描classpath下的那些packages呢?已经定义好了
彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
对外提供的接⼝服务,在Jersey中叫做资源
在这里插入图片描述
这些就是使⽤Jersey发布的供Eureka Client调⽤的Restful⻛格服务接⼝(完成服务注册、⼼跳续约等接⼝)

Eureka Server服务注册接⼝(接受客户端注册服务)

ApplicationResource类的addInstance()⽅法中代码:registry.register(info,“true”.equals(isReplication));
在这里插入图片描述
com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#register - 注册服务信息并同步到其它Eureka节点
在这里插入图片描述
AbstractInstanceRegistry#register():注册,实例信息存储到注册表是⼀个ConcurrentHashMap
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
PeerAwareInstanceRegistryImpl#replicateToPeers() :复制到Eureka对等节点
在这里插入图片描述
PeerAwareInstanceRegistryImpl#replicateInstanceActionsToPeers
在这里插入图片描述

Eureka Server服务续约接⼝(接受客户端续约)

InstanceResource的renewLease⽅法中完成客户端的⼼跳(续约)处理,关键代码:
registry.renew(app.getName(), id, isFromReplicaNode);
在这里插入图片描述
在这里插入图片描述
com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#renew
在这里插入图片描述
replicateInstanceActionsToPeers() 复制Instance实例操作到其它节点
在这里插入图片描述
renew()⽅法中—>leaseToRenew.renew()—>对最后更新时间戳进⾏更新

Eureka Client注册服务

启动过程:Eureka客户端在启动时也会装载很多配置类,我们通过spring-cloud-netflix-eureka-client-2.1.0.RELEASE.jar下的spring.factories⽂件可以看到加载的配置类
在这里插入图片描述
引⼊jar就会被⾃动装配,分析EurekaClientAutoConfiguration类头
在这里插入图片描述
如果不想作为客户端,可以设置eureka.client.enabled=false
在这里插入图片描述

回到主配置类EurekaClientAutoConfiguration

思考:EurekaClient启动过程要做什么事情?

  1. 读取配置⽂件
    在这里插入图片描述
    在这里插入图片描述
    获取配置信息之外就开始获取⼀个Eureka客户端了
    在这里插入图片描述
    来到⽗类,super
    在这里插入图片描述
    在这里插入图片描述
    彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  2. 启动时从EurekaServer获取服务实例信息
    彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
    在这里插入图片描述
    观察⽗类DiscoveryClient()
    在这里插入图片描述
    在另外⼀个构造器中
    彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
    在这里插入图片描述

  3. 注册⾃⼰到EurekaServer(addInstance)
    在这里插入图片描述
    DiscoveryClient#register
    在这里插入图片描述
    底层使⽤Jersey客户端进⾏远程请求。

  4. 开启⼀些定时任务(⼼跳续约,刷新本地服务缓存列表)
    在这里插入图片描述
    刷新本地缓存
    在这里插入图片描述
    彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
    ⼼跳续约定时任务
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  5. 初始化⼀些定时器(定时获取注册信息、发送⼼跳等)
    在这里插入图片描述
    刷新本地缓存定时任务
    在这里插入图片描述
    在这里插入图片描述
    ⼼跳
    在这里插入图片描述
    在这里插入图片描述

  6. 注册⾃⼰
    在这里插入图片描述
    在这里插入图片描述
    服务下架,服务死掉的时候就会调⽤shutdown,就是shutdown
    在这里插入图片描述

Eureka Client下架服务

我们看com.netflix.discovery.DiscoveryClient#shutdown
彻底搞懂 Spring Cloud 前世今生 系列之 第⼀代 Spring Cloud 核⼼组件 ——Eureka
在这里插入图片描述
在这里插入图片描述

CSDN社区 《创作达人》活动,只要参与其中并创作文章就有机会获得官方奖品:精品日历、新程序员杂志,快来参与吧!链接直达 https://bbs.csdn.net/topics/605272551

四四频道