什么是Eureka?Eureka能干什么?Eureka怎么用?
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
注本篇文章主要参考周阳老师讲解的cloud进行整理的
由于代码有很多本篇文章也是尽可能的每一步骤都进行了记录在文章最下方提供了源码地址
一、概念
1.1、什么是服务治理
Spring Cloud 封装了 Netflix
公司开发的 Eureka 模块来实现服务治理
服务治理就是提供了微服务架构中各微服务实例的快速上线或下线且保持各服务能正常通信的能力的方案总称。
服务治理的优点:
- 更高的可用性服务治理可以支持动态的服务实例集群环境,任何服务实例可以随时上线或下线。并且
当一个服务实例不可用时,治理服务器可以将请求转给其他服务提供者
,当一个新的服务实例上线时,也能够快速地分担服务调用请求。 - 负载均衡服务治理可以提供动态的负载均衡功能,可以
将所有请求动态地分布到其所管理的所有服务实例中进行处理
。 - 提升应用的弹性服务治理的客户端会
定时从服务治理服务器中复制一份服务实例信息缓存到本地中
,这样即使当服务治理服务器不可用时,服务消费者也可以使用本地的缓存去访问相应的服务
,而不至于中断服务。通过这种机制,极大地提高了应用的弹性。 - 高可用性集群可以构建服务治理集群,
通过互相注册机制
,将每个治理服务器所管辖的服务信息列表进行交换
,使服务治理服务拥有更高的可用性。
1.2、 什么是Eureka
Eureak
是Netflix
开源微服务框架中一系列项目中的一个。Spring Cloud
对其进行了二次封装,形成了Spring Cloud Netflix
子项目,但未对Netflix
微服务实现原理进行更改,只是进行了Spring Boot
化,使开发者更容易使用和整合。
在Eureka
中,对于服务治理有如下3个概念:
- 服务治理服务器(Eureka服务器) Eureka采用了CS的设计架构
Eureka Server
作为服务注册功能的服务器也就是服务注册中心这里的Eureka Server指的是我们自己专门写一个Java应用来引用Eureka Server的依赖将这个应用作为注册中心
。而系统中的其他微服务使用Eureka
的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行
。 - 服务注册代理(服务提供者)如果一个微服务是一个服务提供者那么可以通过服务注册代理将服务配置信息注册到治理服务器上。服务注册代理可以理解为一个
Eureka
客户端负责将微服务所提供的服务向Eureka
服务器执行注册、续约和注销等操作以使服务消费者可以发现并进行消费。在服务注册时需要向服务治理服务器提供服务名称、宿主服务器IP地址、服务端口号、域名等主要数据
。 - 服务发现客户端(服务消费者)也是一个
Eureka
客户端。它在启动时会默认从所服务治理服务器中获取所有的服务注册表信息通过所获取到的服务注册列表信息来消费相应的服务。
1.3、 Eureka包含两个组件
Eureka Server提供注册服务功能
各个微服务节点通过配置启动后会在EurekaServer中进行注册这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息服务节点的信息可以在界面中直观看到。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
EurekaClient通过注册中心进行访问
EurekaClient可以分为提供者和消费者他们都是一个Java客户端客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳EurekaServer将会从服务注册表中把这个服务节点移除默认90秒
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
1.4、 什么场景使用Eureka
准确来说是什么场景需要使用注册中心
大并发量的应用情况下就需要搭建集群这里的集群指的不是Eureka注册中心集群而是指的微服务各个模块的集群搭建集群我们就需要通过注册中心来实时掌握每个应用的情况如果根本没有大并发场景项目虽然也拆分了服务但是用不到集群那我们大可不必使用注册中心使用注册中心从某种意义上来讲增加了程序的复杂度而且还得时刻维护注册中心有点大材小用了。
1.5、 Eureka停更
关于停更问题我在这篇博客已经讲的很清楚了https://blog.csdn.net/weixin_43888891/article/details/125193088?spm=1001.2014.3001.5501
1.6、代码要实现的内容
二、单机Eureka构建步骤
使用Eureka那就意味着一定是微服务架构这就涉及到了聚合工程本篇博客的代码完全是基于本人上一篇博客 搭建的聚合工程 来进行开发的。
idea聚合工程搭建详解https://blog.csdn.net/weixin_43888891/article/details
2.1、搭建Eureka Server
1、建Modulecloud-eureka-server7001
2、改pom.xml
<?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"><parent><artifactId>mscloud</artifactId><groupId>com.gzl.cn</groupId><version>1.0-SNAPSHOT</version></parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包可以使用Payment支付Entity -->
<dependency>
<groupId>com.gzl.cn</groupId>
<artifactId>cloud-api-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--boot web actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
3、写YML
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己。
register-with-eureka: false
#false表示自己端就是注册中心我的职责就是维护服务实例并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4、主启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaSever7001Application {
public static void main(String[] args) {
SpringApplication.run(EurekaSever7001Application.class, args);
}
}
5、启动测试
2.2、搭建Eureka Client端的提供者
这里我们直接接着上一篇文章中的cloud-provider-payment8001服务进行调整
1、在原有cloud-provider-payment8001服务的pom当中添加以下依赖
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、添加yml
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息默认为true。单节点无所谓集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
3、启动类添加注解
@EnableEurekaClient
4、测试
先要启动EurekaServer确保 http://localhost:7001/ 可以访问
然后再启动cloud-provider-payment8001
微服务注册名配置说明
5、自我保护机制
下面一排红字不用管他是Eureka的自我保护机制在最文章后面我会具体讲他的作用。
2.3、搭建Eureka Client端的消费者
这里我们直接接着上一篇文章中的cloud-provider-payment8001服务进行调整
1、在原有cloud-consumer-order80服务的pom当中添加以下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、添加yml
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息默认为true。单节点无所谓集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
3、启动类添加注解
@EnableEurekaClient
4、测试
先要启动EurekaServer, 7001服务
再启动服务提供者provider, 8001服务
最后启动服务消费者consumer80服务
访问http://localhost/consumer/payment/get/1
三、Eureka集群
通过上面的练习我们会发现根本没体会到Eureka作用是什么没有Eureka服务照样可以运行使用这也就是上面提到的假如微服务不使用集群的话完全没必要使用注册中心。下面我们进行分别搭建Eureka集群和微服务集群。
3.1、Eureka集群原理说明
微服务RPC远程服务调用最核心的是什么
高可用试想你的注册中心只有一个only one 它出故障了那就呵呵(▽)"了会导致整个为服务环境不可用所以需要搭建Eureka集群
3.2、EurekaServer集群环境构建步骤
1、参考cloud-eureka-server7001 新建 cloud-eureka-server7002直接复制就行
2、改pom
3、父工程的pom当中添加model
正常通过ide创建他是会自动在父工程添加model的而我们是复制的所以需要手动添加
4、修改启动名字EurekaSever7002Application
5、修改映射配置
添加
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
6、修改yml7001和7002都需要修改由于7002是直接复制的所以7002的yml端口号需要改成7002
7002主要是修改端口和hostname,7001的yml当中的hostname修改为eureka7001.com
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
7、将 支付服务8001微服务 和 订单服务80微服务 发布到上面2台Eureka集群配置中两个服务都需要修改yml
http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
8、测试
先要启动EurekaServer, 7001/7002服务 http://eureka7001.com:7001/
再要启动服务提供者provider, 8001
再要启动消费者,80
访问http://localhost/consumer/payment/get/1
3.3、支付服务提供者8001集群环境构建
1、参考cloud-provider-payment8001 新建 cloud-provider-payment8002直接复制就行
2、改pom
3、父工程的pom当中添加model
4、修改启动名字PaymentMain8002
5、修改yml主要就是修改端口号为8002
6、修改8001/8002的Controller
主要是方便区分我们调用的是哪个服务
3.4、调整80消费服务
1、订单服务访问地址不能写死
// 通过在eureka上注册过的微服务名称调用
public static final String PaymentSrv_URL = "http://CLOUD-PAYMENT-SERVICE";
2、使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
spring-cloud-starter-netflix-eureka-client
依赖当中就依赖了ribbon
依赖所以我们不用添加ribbon
依赖就能使用他的注解。
一旦地址改为以服务名称访问的形式"http://CLOUD-PAYMENT-SERVICE
"就必须添加这个负载均衡的注解不然访问80服务的接口就会报错。
3、测试
- 先要启动EurekaServer, 7001/7002服务
- 再要启动服务提供者provider, 8001/8002服务
- 然后最后启动80服务
- 访问http://localhost/consumer/payment/get/31
多次访问这个接口返回的日志当中的端口号会交替出现这就是负载均衡。当服务提供者8001和8002任意一个挂掉之后并不会影响服务调用。 - Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号,且该服务还有负载功能了。
3.5、Eureka集群严重问题
在测试过程发现的问题所以记录一下
这时候会发现所有服务全注册到了7001而7002实际上并没有服务当我们把7001服务关闭后会发现过一段时间服务自动就注册到了7002可能需要个几秒这几秒的过程当中如果调用服务是会报错的
为什么会都优先注册到7001而不是7002呢跟配置文件写的顺序有关
假设7001注册中心挂掉的同时8001服务也挂掉了然后先恢复7001服务然后再恢复8001服务。这时候会出现以下情况。8001注册到了7001注册中心而其他没有挂掉的服务由于7001挂掉了之后注册在7001的服务全部转移到了7002注册中心。
这个时候会引发一个非常严重的问题就是服务提供者的集群失效
多次访问80服务的接口会发现一直是调用的8002服务他不会去调用8001因为80服务注册在了7002注册中心而8001注册在了7001注册中心服务都不在一个注册中心所以他根本调用不了。
解决办法 假如注册中心和一个服务挂掉之后一定要先想办法先恢复服务而不是先恢复挂掉的注册中心先恢复8001服务的话他会直接注册到7002注册中心就完全避免了这样的问题。当然这里启动8001服务的时候会报错但是不影响的因为他启动的时候会先去注册到7001然后发现7001挂掉了这时候会报错然后自动注册到7002。
从这个问题也间接的会发现微服务框架当中有时候程序启动的先后顺序至关重要
3.6、主机名称修改 和 ip提示
1、主机名称修改
这里一个是应用名称一个是主机名称
2、ip提示
当我们服务多了有时候以应用名称根本无法快速锁定他在哪台服务器部署所以可以添加以下配置。
3.7、服务发现Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
在8001的PaymentController添加一个接口
DiscoveryClient 导包的时候导下面的包
import org.springframework.cloud.client.discovery.DiscoveryClient;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "/payment/discovery")
public Object discovery() {
// 获取注册的服务
List<String> services = discoveryClient.getServices();
for (String element : services) {
System.out.println(element);
}
// 根据服务名称获取服务详细信息
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance element : instances) {
System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
+ element.getUri());
}
return this.discoveryClient;
}
测试http://localhost:8001/payment/discovery 访问后看控制台输出内容
四、Eureka心跳机制
4.1、什么是心跳机制
在了解保护机制之前我们有必要先了解一下Eureka的心跳机制。
使用注册中心那我们的服务信息就需要注册到注册中心注册中心起到的作用是服务治理那他就需要时刻掌握服务是否宕机心跳机制就是Eureka client一旦注册到注册中心后就需要每隔一段时间告诉Eureka server一下我还是活的。
4.2、Eureka Client心跳频率配置
在每一个Eureka Client启动的时候都会有一个HeartbeatThread的心跳线程这个线程的作用就是保证默认30秒
的时候向Eureka Server发送一个信息的请求告诉Eureka Server当前的Eureka Client还存活着。
下面这个参数可以来配置心跳间隔时间这个是在Eureka的client端配置的
eureka:
instance:
lease-renewal-interval-in-seconds: 30
4.3、Eureka Server端接收到心跳做了什么操作
Eureka Server在接收到请求之后肯定是先去自己的注册表中去找到请求的对应的服务信息在这个服务信息里面有个Lease的对象这个里面就是可以进行心跳续约操作的更新Lease对象里面的LastUpdateTimestamp时间戳每一次接收到都会更新这个时间戳的。
4.4、Eureka Server查看心跳是否收到
Eureka Server在启动的时候启动的时候会每60秒遍历一次注册表中的信息然后查看注册表中的信息是否有过期的如果过期会加入到一个列表里面单独处理。
清理间隔时间配置单位毫秒默认是60*1000在Eureka的server端配置的
eureka:
server:
eviction-interval-timer-in-ms: 60
4.5、Eureka Client心跳最大等待时间
Eureka服务端在收到最后一次心跳后等待时间上限单位为秒(默认是90秒)超时将剔除服务
。
通过下面可以配置等待时间这个是在Eureka的client端配置的
eureka:
instance:
lease-expiration-duration-in-seconds: 90
4.6、总结
通过以上了解我们一共接触了三个时间配置一个是注册中心的扫描过期时间
扫描过期时间就好比租车公司要定期查看哪些车租聘日到期了需要进行收回。还有一个客户端设置的 租期更新时间间隔
这个时间就是租户需要隔一段时间告诉租聘公司我还要继续租这个车还有一个是租期到期时间
这个时间就是假如客户端超过这个时间没有给租聘公司发送心跳那么就认为不租了。
server端:
eureka.server.eviction-interval-timer-in-ms//清理间隔单位毫秒默认是60*1000
client端
eureka.instance.lease-renewal-interval-in-seconds =10//租期更新时间间隔默认30秒
eureka.instance.lease-expiration-duration-in-seconds =30//租期到期时间默认90秒
五、Eureka自我保护机制
首先明确观点Eureka自我保护机制有很多bug而且中文资料很缺乏网上普遍是一篇博客抄来抄去的本人通过案例也确实发现很多bug的地方如果钻牛角尖的话可能几天都学不完
5.1、什么是自我保护机制
保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护
。为了防止EurekaClient可以正常运行但是 与 EurekaServer网络不畅通情况下网络延迟等原因在保护模式开启的情况下EurekaServer不会立刻将EurekaClient服务剔除。
如果在Eureka Server的首页看到以下这段提示则说明Eureka进入了保护模式
这个需要在注册中心配置的
server:
#关闭自我保护机制保证不可用服务被及时踢除默认为true开启的
enable-self-preservation: false
5.2、为什么会出现自我保护机制
一句话某时刻某一个微服务因为网络原因不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存属于CAP里面的AP分支。
因为网络通信是可能恢复的但是Eureka客户端只会在启动时才去服务端注册。如果因为网络的原因而剔除了客户端将造成客户端无法再注册到服务端。为了避免此问题Eureka提供了自我保护机制。
CAP即
- Consistency一致性
- Availability可用性
- Partition tolerance分区容忍性
清理条件
- Eureka服务端会检查最近15分钟内所有Eureka 实例正常心跳占比这个15分钟是在源码当中有个每15分钟执行一次的定时任务如果低于85%就会触发自我保护机制。
- 触发了保护机制Eureka将暂时把这些失效的服务保护起来不让其过期但这些服务也并不是永远不会过期该现象可能出现在如果网络不通但是EurekaClient未出现岩机。
- Eureka在启动完成后每隔60秒会检查一次服务健康状态这个60秒就是上面提到的Eureka Server查看心跳是否收到默认的配置
- 如果这些被保护起来失效的服务过一段时间后默认90秒这个90秒就是上面提到的心跳最大等待时间还是没有恢复就会把这些服务剔除。如果在此期间服务恢复了并且实例心跳占比高于85%时就会自动关闭自我保护机制。
- 此时如果换做别的注册中心如果一定时间内没有收到心跳会将剔除该服务这样就出现了严重失误因为客户端还能正常发送心跳只是网络延迟问题而保护机制是为了解决此问题而产生的。
它的设计哲学就是宁可保留错误的服务注册信息也不盲目注销任何可能健康的服务实例。一句话讲解好死不如赖活着
综上自我保护模式是一种
应对网络异常的安全保护措施
。它的架构哲学是宁可同时保留所有微服务健康的微服务和不健康的微服务都会保留也不盲目注销任何健康的微服务。使用自我保护模式可以让Eureka集群更加的健壮、稳定。
5.3、如何选择关闭还是开启自我保护机制
Eureka服务端默认情况下是会开启自我保护机制的。但我们在不同环境应该选择是否开启保护机制。
自我保护机制的配置是默认是开启的eureka.server.enable-self-preservation=true
一般情况下我们会选择在 开发环境下关闭自我保护机制而在生产环境下启动自我保护机制。
开发环境下我们我们启动的服务数量较少而且会经常修改重启。如果开启自我保护机制很容易触发Eureka客户端心跳占比低于85%的情况。使得Eureka不会剔除我们的服务从而在我们访问的时候会访问到可能已经失效的服务导致请求失败影响我们的开发。
在生产环境下我们启动的服务多且不会反复启动修改。环境也相对稳定影响服务正常运行的人为情况较少。适合开启自我保护机制让Eureka进行管理。
5.4、Eureka控制台参数
如下我启动了3个服务
Lease expiration enabledEureka自动保护机制启动后该值为false。
Renews thresholdEureka Server 期望每分钟收到客户端实例续约的阅值。
Renews threshold = 服务实例总数 *60/续约间隔*自我保护续约百分比阈值因子阈值因子默认85%续约间隔默认是30。
Renews (last min) Eureka Server 最后1分钟收到客户端实例续约的总数。
Renewslast min) = 服务实例总数 * (60/续约间隔
如果自我保护模式开启了且当续约阈值>0上一分钟的续约数>阈值那么可以清理。言外之意就是当上一分钟续约数<阈值那么就不清理保护了
Renews (last min) < Renews threshold
5.5、测试开启了自我保护机制
什么都没配置只是启动了三个服务然后等了一会就进入保护模式了。对于这一点我也不是很理解。进入保护模式后我随便关掉了一个服务Eureka控制台上也就几秒钟立马就消失了并没有向上面所说的进入保护模式后不会轻易移除服务
我开启了自我保护机制并且给每个要注册的服务设置如下配置
eureka:
instance:
#Eureka服务端在收到最后一次心跳后等待时间上限单位为秒(默认是90秒)超时将剔除服务
lease-expiration-duration-in-seconds: 2
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
注意要观察Renews (last min)和Renews threshold值的时候启动项目后一定要等个1分钟才可以等一分钟过后如下
Renews threshold完全跟上面提到的算法是不一致的而且差距还很大而Renews (last min)却差距不是很大。针对于此问题我也搜了很多相关资料由于Eureka已经停更很多人已经弃用并没有太多的人关注这个问题了。
当我关闭8001服务的时候Eureka上的8001服务并没有立马消失而是停留了几秒钟状态显示的是DOWN。
5.6、关闭自我保护机制
eureka:
server:
enable-self-preservation: false
关闭后启动注册中心就会看到以下字样
六、Eureka健康检查
由于server和client通过心跳保持服务状态而只有状态为UP的服务才能被访问
看eureka界面中的status
比如心跳一直正常服务一直UP但是此服务DB连不上了无法正常提供服务
- 我们需要将微服务的健康状态也同步到server
- 只需要启动eureka的健康检查
- 这样微服务就会将自己的健康状态同步到eureka
这个需要在Eureka client端设置而且默认就是开启的。
eureka:
client:
healthcheck:
enabled: true
刚开始我以为是只要这个设置true然后当服务的mysql挂掉后会自动更新注册中心的状态然后可以避免其他服务调用异常的服务然而并不是他还需要配置很多东西并没有我想象的那么神奇
想了解的可以看一下这篇文章https://my.oschina.net/u/3727895/blog/4481621
中文的cloud官网介绍的Eurekahttps://www.bookstack.cn/read/spring-cloud-docs/docs-user-guide-eureka.md
源码地址https://gitee.com/gzl_com/spring-cloud.git
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |