一、Eureka服务注册中⼼
1. 关于服务注册中⼼
注意:服务注册中⼼本质上是为了解耦服务提供者和服务消费者。
对于任何⼀个微服务,原则上都应存在或者⽀持多个提供者(⽐如简历微服务部署多个实例),这是由 微服务的分布式属性决定的。为了⽀持弹性扩缩容特性,原本在单体应⽤阶段常⽤的静态LB机制就不再适⽤了,引入额外的管理为服务提供者注册发现,而这个就是服务注册中心。
1.1 服务注册中⼼⼀般原理
目前Eureka 支持pull 模式,即定时任务主动拉取。
1.2 主流服务中⼼对⽐
- Zookeeper :简单来说zookeeper本质=存储+监听通知。。另外,Zookeeper可⽤性也可以,因为只要半数以上的选举节点存活,整个集群就是可⽤的。根据半数原则,固有了集群最优节点个数是奇数(3),不是偶数(4),因为不论是3个节点还是4个节点,都是只允许一个节点服务不可用。容错率是一样的。
- Eureka : 由Netflix开源,并被Pivatal集成到SpringCloud体系中,它是基于 RestfulAPI ⻛格开发的服务注册 与发现组件。
- Consul :是由HashiCorp基于Go语⾔开发的⽀持多数据中⼼分布式⾼可⽤的服务发布和注册服务软 件, 采⽤Raft算法保证服务的⼀致性,且⽀持健康检查。
- Nacos : Nacos是⼀个更易于构建云原⽣应⽤的动态服务发现、配置管理和服务管理平台。简单来说 Nacos 就是 注册中⼼ + 配置中⼼的组合,帮助我们解决微服务开发必会涉及到的服务注册 与发现,服务 配置,服务管理等问题。Nacos 是 Spring Cloud Alibaba 核⼼组件之⼀,负责服务注册与发现, 还有配置。
2. Eureka
- Eureka 基础架构
- Eureka 交互流程及原理
Eureka通过⼼跳检测、健康检查和客户端缓存等机制,提⾼系统的灵活性、可伸缩性和可⽤性。
3. Eureka应⽤及⾼可⽤集群
3.1 Eureka Server (单实例和集群)搭建注意细节
这里就不详细贴搭建erueka 的服务细节代码了,主要注意下搭建时候,父工程需要引⼊Jaxb以及cloud和boot两个依赖管理。如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zjn</groupId>
<artifactId>eureka</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>eureka-server</module>
</modules>
<dependencies>
<!--引⼊Jaxb,开始-->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.11</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.2.10-b140310.1920</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!--引⼊Jaxb,结束-->
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!--编译插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
<!--打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
小贴士:搭建集群时候可以使用同一个yml文件拆分(只适合个人快捷搭建,方便测试,不适合生产环境),如下:
#Eureka server服务端⼝
spring:
application:
name: zjn-cloud-eureka-server
---
spring:
profiles: ZjnCloudEurekaServerA
server:
port: 8761
eureka:
instance:
hostname: zjna
client:
service-url:
defaultZone: http://zjnb:8762/eureka/
register-with-eureka: true
fetch-registry: true
---
spring:
profiles: ZjnCloudEurekaServerB
server:
port: 8762
eureka:
instance:
hostname: zjnb
client:
service-url:
defaultZone: http://zjna:8761/eureka/
register-with-eureka: true
fetch-registry: true
idea启动可设置active-profiles 指定启动文件
注意:
- 1)从Spring Cloud Edgware版本开始,@EnableDiscoveryClient 或 @EnableEurekaClient 可省 略。只需加 上相关依赖,并进⾏相应配置,即可将微服务注册到服务发现组件上。
- 2)@EnableDiscoveryClient和@EnableEurekaClient⼆者的功能是⼀样的。但是如果选⽤的是 eureka服务器,那么就推荐@EnableEurekaClient,如果是其他的注册中⼼,那么推荐使⽤ @EnableDiscoveryClient,考虑到通⽤性,后期我们可以使⽤@EnableDiscoveryClient
3.2 Eureka Client 搭建注意细节(单注册以及注册到server集群)
- ⽗⼯程中引⼊spring-cloud-commons依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
- client 引入 坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- yml配置
server:
port: 9006
eureka:
client:
serviceUrl: # eureka server的路径
defaultZone: http://zjna:8761/eureka/,http://zjnb:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写⼀台,因为各个eureka server 可以同步注册表
instance:
#使⽤ip注册,否则会使⽤主机名注册了(此处考虑到对⽼版本的兼容,新版本经过实验都是ip)
prefer-ip-address: true
#⾃定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
instance-id: ${spring.cloud.client.ipaddress}:${spring.application.name}:${server.port}:@project.version@
spring:
application:
name: zjn-client
- 启动类添加 @EnableDiscoveryClient
- 最后注意下要添加成web应用,不然不会一直运行,上面的instance-id 可自定义实例名称增加@project.version@版本号,进行客户端版本控制
4. Eureka细节详解
4.1 Eureka元数据详解
Eureka的元数据有两种:标准元数据和⾃定义元数据。
- 标准元数据:主机名、IP地址、端⼝号等信息,这些信息都会被发布在服务注册表中,⽤于服务之间的 调⽤。
- ⾃定义元数据:可以使⽤eureka.instance.metadata-map配置,符合KEY/VALUE的存储格式。这 些元 数据可以在远程客户端中访问。
instance:
prefer-ip-address: true
metadata-map:
# ⾃定义元数据(kv⾃定义)
cluster: cl1
region: rn1
4.2 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⾃动进⼊⾃我保护机制。
当处于⾃我保护模式时
- 1)不会剔除任何服务实例(可能是服务提供者和EurekaServer之间⽹络问题),保证了⼤多数服务依 然可⽤
- 2)Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节 点依然可⽤,当⽹络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
- 3)在Eureka Server⼯程中通过eureka.server.enable-self-preservation配置可⽤关停⾃我保护,默认 值是打开
eureka:
server:
enable-self-preservation: false # 关闭⾃我保护模式(缺省为打开)
5. Eureka核⼼源码剖析
5.1 Eureka Server启动过程
- ⼊⼝:SpringCloud充分利⽤了SpringBoot的⾃动装配的特点,使用了SPI机制,在boot启动时装载了EurekaServerAutoConfiguration⾃动配置类,如下:
- EurekaServerAutoConfiguration类 需要有⼀个marker bean,才能装配Eureka Server,那么这个marker其实是由@EnableEurekaServer注解决定 的,如下:
也就是说只有添加了@EnableEurekaServer注解,才会有后续的动作,这是成为⼀个EurekaServer的前提
- 重点关注EurekaServerAutoConfiguration,里面把仪表盘、对等节点注册器,封装对等节点的相关操作,如同时更新节点,
- 在com.netflix.eureka.cluster.PeerEurekaNodes#start⽅法中会构建线程池
- 回到主配置类中,eurekaServerContext 创建eurekaServer上下文
- 进入到 eurekaServerContext 中,可以看到init方法,会启动上面更新对等节点的线程池start()方法。
- 回到主配置类中,看到 eurekaServerBootstrap 也注册成@Bean组件,如下:
- 接着注册Jersey过滤器,如下:
- 重新进入到org.springframework.cloud.netflix.eureka.server.EurekaServerInitializerConfiguration
- 进入org.springframework.cloud.netflix.eureka.server.EurekaServerBootstrap#contextInitialized
- 重点关注initEurekaServerContext()
- 研究⼀下上图中的syncUp⽅法
- 研究⼀下上图中的syncUp⽅法 继续研究com.netflix.eureka.registry.AbstractInstanceRegistry#register(提供实例注册功能)
- 继续研究com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#openForTraffic
- 进⼊postInit()⽅法查看
总结启动流程 :
1、 用SPI机制自动启动时装载了EurekaServerAutoConfiguration⾃动配置类,标记,标记@EnableEurekaServer,可进行自动配置。
2、 EurekaServerAutoConfiguration,里面把仪表盘、对等节点注册器,封装对等节点的相关操作,如同时更新节点
3、 PeerEurekaNodes构建线程池,更新对等节点信息
4、 eurekaServerContext#initiallize 启动PeerEurekaNodes中的线程。
5、 构建eurekaServerBootstrap启动类
6、 注册Jersey过滤器
7、 初始化context,注册统计器
8、 AbstractInstanceRegistry#register 实例注册到map
9、 开启定时
10、
5.2 Eureka Server服务接⼝暴露策略
- 在Eureka Server启动过程中主配置类注册了Jersey框架(是⼀个发布restful⻛格接⼝的框架,类似于我 们的springmvc)
- 进入 Jersey
- 点击EUREKA_PACKAGES,发现扫包”com.netflix.discovery”, “com.netflix.eureka”
- 来到 com.netflix.eureka.resources.ApplicationResource#addInstance 这里就是使⽤Jersey发布的供EurekaClient调⽤的Restful⻛格服务接⼝(完成服务注册、⼼跳续约等接⼝)
5.3 Eureka Server服务注册接⼝(接受客户端注册服务)
- 点进register 找到实现类 com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#register 注册服务信息并同步到其它Eureka节点
- 点击super.register 来到 com.netflix.eureka.registry.AbstractInstanceRegistry#register,注册,实例信息存储到注册表是⼀个ConcurrentHashMap
Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
- 回到 com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateToPeers 复制到Eureka对等节点
- 进入 com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateInstanceActionsToPeers
5.4 Eureka Server服务续约接⼝(接受客户端续约)
- com.netflix.eureka.resources.InstanceResource#renewLease⽅法中完成客户端的⼼跳(续约)处理,关键代码: registry.renew(app.getName(), id, isFromReplicaNode);
- com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl#replicateToPeers#replicateInstanceActionsToPeers 复制Instance实例操作到其它节点
总结: renew()⽅法中—>leaseToRenew.renew()—>对最后更新时间戳进⾏更新
5.5 Eureka Client注册服务
- 启动过程:Eureka客户端在启动时也会装载很多配置类,我们通过spring-cloud-netflix-eureka-client- 2.1.0.RELEASE.jar下的spring.factories⽂件可以看到加载的配置类EurekaClientAutoConfiguration
- 如果不想作为客户端,可以设置eureka.client.enabled=false
- 进入 org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration
- client启动做的事:
- 1)读取配置⽂件
- 2)启动时从EurekaServer获取服务实例信息
- 3)注册⾃⼰到EurekaServer(addInstance)
- 4)开启⼀些定时任务(⼼跳续约,刷新本地服务缓存列表)
5.5 Eureka Client下架服务
- com.netflix.discovery.DiscoveryClient#shutdown
- com.netflix.discovery.DiscoveryClient#unregister
来自lagouedu 笔记整理