Eureka基本原理。
通过上图我们可以看出,服务提供者在启动的时候需要向注册中心注册自己的信息,而注册中心把向自己注册的服务提供者都保存下来,以便服务消费者获取用来发起请求,而服务消费者需要从注册中心获取服务提供者列表,然后向服务提供者发起调用。
基本流程:
- 客户端发起服务注册
- 服务端保存注册信息到注册表
- 客户端定时发生心跳检测
- 服务端服务剔除及自我保护
- 客户端发起服务下线
- 客户端或者服务端注册信息到本地内存
- 客户端整合服务发现
开源代码很简单,从git上下载就行,目录大概是这样。
pom文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.mhyr</groupId>
<artifactId>mhyr-eureka</artifactId>
<version>1.0-SNAPSHOT</version>
<name>mhyr-eureka</name>
<description>注册中心</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.1</spring-cloud.version>
<apollo.version>1.9.0</apollo.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 集成apollo -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo.version}</version>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-core</artifactId>
<version>${apollo.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>mhyr-eureka</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml文件配置:
#服务端口
server:
port: 8961
#服务ID
app:
id: mhyr-member-plat
#服务名称
spring:
application:
name: mhyr-eureka
#--------------------------单机模式--------------------------#
#eureka:
# instance:
# instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
# prefer-ip-address: true
# ip-address: localhost
# #服务续约(renew)的间隔,默认为30秒
# lease-renewal-interval-in-seconds: 30
# #服务失效时间
# lease-expiration-duration-in-seconds: 90
# server:
# # 设置eureka是否启动自我保护 true指开启eureka的自我保护 false指关闭eureka的自我保护
# # 如果关闭eureka的自我保护,则不可用的服务会被及时剔除掉
# enable-self-preservation: false
# # 剔除服务的时间间隔毫秒数(单位:毫秒) 扫描失效服务的时间间隔(默认是60*1000 即60秒)
# eviction-interval-timer-in-ms: 5000
#
# client:
# register-with-eureka: false # 表示是否向Eureka注册中心注册自己
# fetch-registry: false # 如果为false 则表示自己为注册中心
# service-url:
# defaultZone: http://localhost:8762/eureka/
#--------------------------集群模式--------------------------#
eureka:
instance:
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
prefer-ip-address: true
ip-address: 127.0.0.1
#服务续约(renew)的间隔,默认为30秒
lease-renewal-interval-in-seconds: 30
#服务失效时间
lease-expiration-duration-in-seconds: 60
server:
# 设置eureka是否启动自我保护 true指开启eureka的自我保护 false指关闭eureka的自我保护
# 如果关闭eureka的自我保护,则不可用的服务会被及时剔除掉
enable-self-preservation: false
# 剔除服务的时间间隔毫秒数(单位:毫秒) 扫描失效服务的时间间隔(默认是60*1000 即60秒)
eviction-interval-timer-in-ms: 5000
client:
register-with-eureka: true # 表示是否向Eureka注册中心注册自己
fetch-registry: true # false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: ${app.eureka.defaultZone} #注册的注册中心集群配置
#集成apollo配置
apollo:
bootstrap:
enabled: false
namespaces: application
eagerLoad:
enabled:
meta: http://mhyr-config:8080 #apollo访问地址
注册中心维护页面
几种注册中心比较:
服务注册
服务注册的原理主要涉及到eureka server的存储结构,采用一个三层缓存的结构。具体内部的实现逻辑参考二中的图。
层级 | 名称 | 实现方式 | 更新方式 | 数据变更 |
---|---|---|---|---|
第一层 | readOnlyCacheMap(只读) | ConcurrentHashMap | 定时更新(默认30s) | 定时拉取readWriteCacheMap |
第二层 | readWriteCacheMap(读写) | guava | 实时更新 | guava的load机制 |
第三层 | register(注册表) | 双层ConcurrentHashMap | 实时更新 | 客户端的注册、续约、下线 |
服务续约
当服务提供者完成服务信息注册后,会维持一个心跳,定时向eureka server 发送rest请求,告诉其还活着。默认心跳间隔30s。
服务获取
eureka client会定期(默认30s)向eureka server获取获取注册的服务信息,这个获取分为全量获取和增量获取。默认配置下,当客户端首次启动后,会向服务端发起一次全量获取并缓存本地信息,之后每隔30s发起一次增量获取,更新本地缓存
服务调用
通常服务间调用使用组件feign,发起rest请求;其内集成了ribbon,ribbon默认使用了轮训的负载策略,会将eureka client拉取的注册信息拉取到自己这,实现负载。
关于feign和ribbon会在后续学习中具体讲解。
服务下线
表示要从注册中心删除该服务的注册信息,使该服务不能被调用。
服务下线的方式:
方式 | 实现 | 效果 |
---|---|---|
直接停服务 | 直接kill服务 | 90s内注册中心检测到服务无续约,才删除,无法立即下线 |
通过注册中心接口强制下线 | 向eureka 注册中心发送delete | 默认30s的心跳机制,如果在这段时间没有停掉服务,那么会让该服务再次上线 |
客户端主动下线 | @GetMapping("/offline") public void offline(){ DiscoveryManager.getInstance().shutdownComponent(); } | 优雅的下线服务 |
失效剔除
在eureka server中有一个定时任务Evict,该任务默认每60s执行一次,其作用域在readWriteCacheMap和register上。
当有服务提供者在默认90s时间内,没有进行服务续约,当Evict执行时,会对这样失效的注册信息进行剔除。通常是宕机的服务或者强制kill的服务。
eureka 的自我保护机制
当服务提供者向注册中心注册完自己的信息之后,服务提供者会定期的续约(服务提供者和注册中⼼通信),假如服务提供者和注册中⼼之间的⽹络有点问题,不代表服务提供者不可⽤,不代表服务消费者⽆法访问服务提供者。如果在15分钟内超过85%的客户端节点都没有正常的⼼跳,那么Eureka就认为客户端与注册中⼼出现了⽹络故障,Eureka Server⾃动进⼊⾃我保护机制。
当处于⾃我保护模式时eureka server不会剔除任何服务实例(可能是服务提供者和EurekaServer之间⽹络问题),保证了⼤多数服务依然可⽤;Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可⽤,当⽹络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。