Eureka
一 什么是SpringCloud?
Author:呆萌老师 QQ:2398779723 微信:it_daimeng
Spring Cloud是一个微服务框架,相比Dubbo等RPC框架, Spring Cloud提供的全套的分布式系统解决方案,是若干个框架的集合。
Spring Cloud为微服务架构开发涉及的配置管理,服务治理,熔断机制,智能路由,微代理,控制总线,一次性token,全局一致性锁,leader选举,分布式session,集群状态管理等操作提供了一种简单的开发方式。
Spring Cloud 为开发者提供了快速构建分布式系统的工具,开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。
SpringCloud包含了很多子项目:
-
Spring Cloud Config:配置管理工具,支持使用Git存储配置内容,支持应用配置的外部化存储,支持客户端配置信息刷新、加解密配置内容等
-
Spring Cloud Bus:事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与Spring Cloud Config联合实现热部署。
-
Spring Cloud Netflix:针对多种Netflix组件提供的开发工具包,其中包括Eureka、Hystrix、Zuul、Archaius等。
Netflix Eureka:一个基于rest服务的服务治理组件,包括服务注册中心、服务注册与服务发现机制的实现,实现了云端负载均衡和中间层服务器的故障转移。
Netflix Hystrix:容错管理工具,实现断路器模式,通过控制服务的节点,从而对延迟和故障提供更强大的容错能力。
Netflix Ribbon:客户端负载均衡的服务调用组件。
Netflix Feign:基于Ribbon和Hystrix的声明式服务调用组件。
Netflix Zuul:微服务网关,提供动态路由,访问过滤等服务。
Netflix Archaius:配置管理API,包含一系列配置管理API,提供动态类型化属性、线程安全配置操作、轮询框架、回调机制等功能。
-
Spring Cloud for Cloud Foundry:通过Oauth2协议绑定服务到CloudFoundry,CloudFoundry是VMware推出的开源PaaS云平台。
-
Spring Cloud Sleuth:日志收集工具包,封装了Dapper,Zipkin和HTrace操作。
-
Spring Cloud Data Flow:大数据操作工具,通过命令行方式操作数据流。
-
Spring Cloud Security:安全工具包,为你的应用程序添加安全控制,主要是指OAuth2。
-
Spring Cloud Consul:封装了Consul操作,consul是一个服务发现与配置工具,与Docker容器可以无缝集成。
-
Spring Cloud Zookeeper:操作Zookeeper的工具包,用于使用zookeeper方式的服务注册和发现。
-
Spring Cloud Stream:数据流操作开发包,封装了与Redis,Rabbit、Kafka等发送接收消息。
-
Spring Cloud CLI:基于 Spring Boot CLI,可以让你以命令行方式快速建立云组件。
Eureka是spring cloud中的一个负责服务注册与发现的组件。
一个Eureka中分为eureka server和eureka client。其中eureka server是作为服务的注册与发现中心。eureka client既可以作为服务的生产者(服务注册),又可以作为服务的消费者(服务发现)。
如图所示:
基本原理:
服务启动后向Eureka注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册中心获取服务提供者地址,然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中取,完成一次调用。
Eureka使用需要服务器端和客户端,他们都需要使用到SpringCloud版本,所以这里我们使用maven父子工程来处理。
创建一个最简单的SpringBoot项目
修改pom.xml文件
添加版本管理器,添加SpringCloud版本,子项目里就不用设置版本号了,将pom文件中的dependencies和build删除,只需要这些:
<!-- springcloud版本 只是对版本进行管理,不会实际引入jar -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
修改packaging的类型为pom,代表父工程只有pom文件
<!-- 父类型都为pom类型 -->
<packaging>pom</packaging>
父工程中的src等文件夹也可以删除
在父工程上右键->new Module–>选择maven–>next
输入子工程的名字
在pom文件中添加jar包
<dependencies>
<!-- eureka-server需要的jar包 版本号不需要设置 因为父工程中已经设置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
创建项目入口类,并添加启动EurekaServer的注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pc1yc7L2-1668090783798)(pic/9.png)]
创建application.yml文件
添加配置信息
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
此配置信息可以在官网中获取:
启动测试:
浏览器中输入http://localhost:8761访问,出来以下页面代表成功
创建子工程2作为Eureka的Client端
创建一个子工程,方法同上
添加jar包
<dependencies>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
创建SpringBoot项目入口类,并添加EurekaClient注解
添加配置信息
测试:
启动客户端,刷新服务器端地址,可以看到服务USERS已注册到服务器端
创建子工程3作为Eureka的另一个Client端,添加
方法同上
添加jar包
<dependencies>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
创建SpringBoot项目入口类,并添加EurekaClient注解
添加配置信息,注意修改一下端口号,避免和eureka_02冲突
重启服务器和两个客户端
测试:
Author:呆萌老师 QQ:2398779723 微信:it_daimeng
在生产环境上,如果任何人输入地址直接就可以进入到Eureka服务治理界面,这样很容易被别人盗取信息,非常不安全。所以我们需要给Eureka添加安全验证。
给Eureka添加安全验证,可以使用Spring Security来实现。
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架(简单说是对访问权限进行控制嘛)。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
spring:
security:
user:
name: root
password: 123
可以看到有登录页面了。
在Eureka服务端,我们加入了Spring Security,而 Spring Cloud 2.0 以上的security默认启用了csrf检验,所以我们需要在eurekaServer端的csrf检验中过滤掉Eureka客户端的路径,否则服务无法注册进 eureka注册中心。
package com.test.eureka.config;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
//注意添加注解
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity httpSecurity) throws Exception {
//让csrf忽略eureka路径 不做csrf验证
httpSecurity.csrf().ignoringAntMatchers("/eureka/**");
super.configure(httpSecurity);
}
}
重新启动客户端
刷新Eureka服务管理页面,可以看到注册进去了
Author:呆萌老师 QQ:2398779723 微信:it_daimeng
我们前面搭建的Eureka服务器是单节点的,如果这个点发生故障,整个服务就会瘫痪,称为单点故障,所以我们需要搭建成集群,一个点出问题,还有另一个点顶上去,代替这个点工作,从而实现高可用、高性能。
实现原理:
在Eureka高可用架构中,Eureka Server也可以作为Client向其他server注册,多节点相互注册组成Eureka集群,集群间相互视为peer(同行)。Eureka Client向Server注册、续约、更新状态时,接收节点更新自己的服务注册信息后,逐个同步至其他peer节点
配置信息稍有不同,其它都一样。
启动两台服务器:
因为前面设置了将自己注册进去,所以可以看到各自都有自己的服务器
修改两个客户端的配置文件,将两个服务器地址都加上
启动客户端后,查看服务注册中心页面:
会发现两个客户端都只在一个服务器中出现,可能是8761也可能是8762
修改两个服务器的配置信息
重新启动两个服务器,因为需要用到对方服务器,所以一次重启一个,不要同时重启。
可以看到两个服务器中都有注册的服务了。
访问某一个服务:
将其中的一台服务器关闭,仍然可以访问。这样就实现了高可用。
从CAP理论看,Eureka是一个AP系统,优先保证可用性(A)和分区容错性§,不保证强一致性©,只保证最终一致性,因此在架构中设计了较多缓存。
Eureka Server存在三个变量:(registry、readWriteCacheMap、readOnlyCacheMap)保存服务注册信息。
包括注册、取消注册等,都直接操作在registry上,同时也会更新recentlyChangedQueue和readWriterCacheMap
读默认是从readOnlyCacheMap读取,读不到的话再从readWriterCacheMap,还是没有再从registry。默认情况下定时任务每30s将readWriteCacheMap同步至readOnlyCacheMap。每60s清理超过90s未续约的节点。
Eureka Client每30s从readOnlyCacheMap更新服务注册信息,而UI则从registry更新服务注册信息。
三级缓存
缓存 | 类型 | 说明 |
---|---|---|
registry | ConcurrentHashMap | 实时更新,类AbstractInstanceRegistry成员变量,UI端请求的是这里的服务注册信息 |
readWriteCacheMap | Guava Cache/LoadingCache | 实时更新,类ResponseCacheImpl成员变量,缓存时间180秒 |
readOnlyCacheMap | ConcurrentHashMap | 周期更新,类ResponseCacheImpl成员变量,默认每30s从readWriteCacheMap更新,Eureka client默认从这里更新服务注册信息,可配置直接从readWriteCacheMap更新 |
缓存相关配置
配置 | 默认 | 说明 |
---|---|---|
eureka.server.useReadOnlyResponseCache |
true | Client从readOnlyCacheMap更新数据,false则跳过readOnlyCacheMap直接从readWriteCacheMap更新 |
eureka.server.responsecCacheUpdateIntervalMs |
30000 | readWriteCacheMap更新至readOnlyCacheMap周期,默认30s |
eureka.server.evictionIntervalTimerInMs |
60000 | 清理未续约节点(evict)周期,默认60s |
eureka.instance.leaseExpirationDurationInSeconds |
90 | 清理未续约节点超时时间,默认90s |
关键类
类名 | 说明 |
---|---|
com.netflix.eureka.registry.AbstractInstanceRegistry |
保存服务注册信息,持有registry和responseCache成员变量 |
com.netflix.eureka.registry.ResponseCacheImpl |
持有readWriteCacheMap和readOnlyCacheMap成员变量 |
Eureka Client 启动时会全量拉取服务列表,启动后每隔 30 秒从 Eureka Server 量获取服务列表信息,并保持在本地缓存中。
服务调用时,客户端会先从本地缓存找到调用服务,如果调取不到 先从注册中心刷新注册表,再同步到本地
二级缓存
缓存 | 类型 | 说明 |
---|---|---|
localRegionApps | AtomicReference | 周期更新,类DiscoveryClient成员变量,Eureka Client保存服务注册信息,启动后立即向Server全量更新,默认每30s增量更新 |
upServerListZoneMap | ConcurrentHashMap | 周期更新,类LoadBalancerStats成员变量,Ribbon保存使用且状态为UP的服务注册信息,启动后延时1s向Client更新,默认每30s更新 |
缓存相关配置
配置 | 默认 | 说明 |
---|---|---|
eureka.instance.leaseRenewalIntervalInSeconds |
30 | Eureka Client 续约周期,默认30s |
eureka.client.registryFetchIntervalSeconds |
30 | Eureka Client 增量更新周期,默认30s(正常情况下增量更新,超时或与Server端不一致等情况则全量更新) |
ribbon.ServerListRefreshInterval |
30000 | Ribbon 更新周期,默认30s |
关键类
类名 | 说明 |
---|---|
com.netflix.discovery.DiscoveryClient |
Eureka Client 负责注册、续约和更新,方法initScheduledTasks()分别初始化续约和更新定时任务 |
com.netflix.loadbalancer.PollingServerListUpdater |
Ribbon 更新使用的服务注册信息,start初始化更新定时任务 |
com.netflix.loadbalancer.LoadBalancerStats |
Ribbon,保存使用且状态为UP的服务注册信息 |
同时对于服务调用,如果涉及到 ribbon 负载均衡,那么 ribbon 对于这个实例列表也有自己的缓存,这个缓存定时(默认30秒)从 Eureka Client 的缓存更新。
这么多的缓存机制可能就会造成一些问题,一个服务启动后可能最长需要 90s 才能被其它服务感知到:
1、首先,Eureka Server 维护每 30s 更新的响应缓存
2、Eureka Client 对已经获取到的注册信息也做了 30s 缓存
3、负载均衡组件 Ribbon 也有 30s 缓存
这三个缓存加起来,就有可能导致服务注册最长延迟 90s ,这个需要我们在特殊业务场景中注意其产生的影响
在生产环境下,我们可以修改Eureka Client缓存的定期更新周期:
eureka.client.registryFetchIntervalSeconds默认30秒,可以修改,比如设置为5秒。
还可以禁用readOnlyCacheMap,直接从readWriteCacheMap获取服务列表。
eureka.server. useReadOnlyResponseCache=false
Author:呆萌老师 QQ:2398779723 微信:it_daimeng
- 服务器启动成功,等待客户(服务)端注册,在启动过程中如果我们配置了集群,集群之间会同步注册表,每一个Eureka serve都会存在这个集群完整的服务注册表信息
- Eureka client 启动时根据配置信息,去注册到指定的注册中心
- Eureka client会每30秒向Eureka server 发送一次心跳请求,证明该客户端服务正常
- 当Eureka server90s内没有接受客户端服务正常,注册中心会认为该节点失效,会注销该实列 (从注册表中删除注册信息)
- 单位时间内如果服务端统计到大量客户端没有发送心跳,则认为网络异常,进去自我保护机制,不在剔除没有发送心跳的客户端
- 当客户端恢复正常之后,服务端就会退出自我保护模式
eureka:
instance:
#eureka客户端需要多长时间发送心跳给eureka服务器,表明他仍然或者,默认30秒
lease-renewal-interval-in-seconds: 5
#eureka服务器在接受到实力的最后一次发出的心跳后,需要等待多久才可以将此实力删除
lease-expiration-duration-in-seconds: 10
Author:呆萌老师 QQ:2398779723 微信:it_daimeng
默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
1、Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
2、Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。
Eureka自我保护机制,通过配置eureka.server.enable-self-preservation
来true打开/false禁用自我保护机制,默认打开状态,建议生产环境打开此配置。
开发环境中如果要实现服务失效能自动移除,只需要修改以下配置。
eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 3000
# 默认90秒
lease-expiration-duration-in-seconds: 10
# 默认30秒
lease-renewal-interval-in-seconds: 3
上,保证当前节点依然可用。
3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。
Eureka自我保护机制,通过配置eureka.server.enable-self-preservation
来true打开/false禁用自我保护机制,默认打开状态,建议生产环境打开此配置。
开发环境中如果要实现服务失效能自动移除,只需要修改以下配置。
eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 3000
# 默认90秒
lease-expiration-duration-in-seconds: 10
# 默认30秒
lease-renewal-interval-in-seconds: 3