1、Eureka基础知识
1.1、什么是服务治理
SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理。
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
1.2、什么是服务注册
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心,而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持 心跳链接 。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息(比如:服务地址、通讯地址等)以别名方式注册到注册中心中。另一方(消费者/服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))
下左图是Eureka系统架构,右图是Dubbo系统架构
1.3、Eureka包含两个组件:Eureka Server 和 Eureka Client
- Eureka Server提供服务注册中心
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
- Eureka Client通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中表把这个服务节点移除(默认90秒)
2、单机Eureka构建步骤
2.1、IDEA生成EurekaServer端服务注册中心 类似物业公司
2.1.1、建Module
2.1.2、改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<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>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.1.3、application.yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
#集群指向其它eureka
# defaultZone: http://eureka7002.com:7002/eureka/
#单机就是7001自己
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
2.1.4、主启动类
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @create 2020-12-13 22:09
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
2.1.5、测试http://localhost:7001/,No instances available没有服务被发现 因为没有注册服务进来当前不可能有服务被发现
2.2、EurekaClient端cloud-provider-payment8001 将注册进EurekaServer成为服务提供者provider,类似于尚硅谷学校对外提供授课服务
2.2.1、改POM
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.2.2、application.yml
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
defaultZone: http://localhost:7001/eureka
2.2.3、主启动类
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @create 2020-12-07 16:58
*/
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
2.2.4、测试,先启动EurekaServer,http://localhost:7001/
2.3、EurekaClient端cloud-consumer-order80 将注册进EurekaServer成为服务消费者consumer,类似于尚硅谷学校上课消费的各位同学
2.3.1、改POM
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.3.2、application.yml
server:
port: 80
spring:
application:
name: cloud-order-service
http: #解决输出中文信息到页面为乱码的问题
encoding:
charset: UTF-8
force: true
enabled: true
#zipkin:
# base-url: http://localhost:9411
#sleuth:
# sampler:
# probability: 1
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true,反之false。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
# 单机
defaultZone: http://localhost:7001/eureka
2.3.3、主启动类
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @create 2020-12-10 13:31
*/
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
2.2.5、测试:先启动EurekaServer7001服务,先启动服务提供者provider8001服务,再启动Order80
Eureka服务器:
查询:http://192.168.3.5:8001/payment/get/4
3、集群Eureka构建步骤
3.1、Eureka集群原理说明
服务注册中心Eureka Server中分为 服务注册 、服务发现,服务注册过程将服务信息注册进服务注册中心,服务发现过程从服务注册中心上获取服务信息,而这个过程的实质就是:将服务名作为key存储,然后根据value取得服务的调用地址
整个Eureka的过程如下:
- 先启动Eureka注册中心
- 启动服务提供者服务
- 服务提供者服务将自身信息(比如服务地址)以别名方式注册到Eureka注册中心
- 消费者服务在需要调用接口时,使用服务别名到注册中心获取实际的RPC远程调用地址
- 消费者获得调用地址后,底层实际是利用 HttpClient 技术实现远程调用
- 消费者获得服务地址后会缓存字本地JVM内存中,默认每间隔30秒更新一次服务调用地址
那么微服务RPC远程服务调用最核心的是:高可用
如果注册中心只有一个,而这个注册中心出现了故障,那么整个微服务就直接GG了,整个微服务环境就不可用了,所以应该搭建Eureka注册中心集群, 实现 负载均衡 + 故障容错
那怎么实现Eureka注册中心的集群呢?用一句话总结就是——互相注册,相互守望,如下图所示:
服务注册中心实现相互注册,让彼此都知道对方的存在,也就是注册中心集群中的每一个注册中心都知道整个集群中的其他注册中心,比如如果有三个注册服务中心7001,7002,7003,那么就将7002和7003注册给7001, 将7002和7001注册给7003, 将7003和7001注册给7002, 以此类推,而这些个注册服务中心作为一个整体对外看做一个注册服务中心。
3.2、EurekaServer集群环境构建步骤
3.2.1、参考cloud-eureka-server7001新建一个服务注册中心cloud-eureka-server7001
3.2.2、改POM,copy复制cloud-eureka-server7001的POM文件即可
3.2.3、修改映射配置,找到C:\Windows\System32\drivers\etc路径下的hosts文件,将其内容修改成如下内容:
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
3.2.4、写配置文件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/
而现在已经有两个注册中心,可以看做两台机器,显然 hostname 不能再叫localhost,而集群不能再这样,对于7001端口的注册中心,修改其配置文件:
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 互相注册,相互守望
defaultZone: http://eureka7002.com:7002/eureka/
首先更改了其服务端的实例名称,最重要的是在defaultZone中将自己注册给7002,举一反三,7002的配置文件显然如下:
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
# 互相注册,相互守望
defaultZone: http://eureka7001.com:7001/eureka/
这样就实现了两个服务注册中心的相互注册
3.2.5、主启动类
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @create 2021-01-17 12:53
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class,args);
}
}
3.2.6、测试访问:http://eureka7001.com:7001/,http://eureka7002.com:7002/
3.3、订单支付两个微服务注册进Eureka集群
3.3.1、将支付服务8001微服务,将订单服务80微服务发布到上面2台Eureka集群配置中,修改YML配置文件:将单机改为集群
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
3.3.2、测试访问:http://eureka7001.com:7001/,http://eureka7002.com:7002/
首先 要启动EurekaServer服务,即7001和7002服务,这样就有了服务注册中心,然后 再启动服务提供方即8001, 最后启动服务消费方即80。如图:7001和7002已经构成集群,且都可以拉取到80和8001两个服务:
调用测试:http://192.168.3.5:8001/payment/get/4
3.4、支付服务提供者8001集群环境搭建
3.4.1、参考8001服务新建8002服务
3.4.2、改POM:和8001的POM文件一样
3.4.3、写配置文件:将端口改为8002,其他和8001相同,两个微服务 对外暴露的服务名相同 均为cloud-payment-service 从而构成集群。
server:
port: 8002
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: com.mysql.jdbc.Driver # mysql驱动包
url: jdbc:mysql://192.168.3.3:3306/springcloud-2020?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
http: #解决输出中文信息到页面为乱码的问题
encoding:
charset: UTF-8
force: true
enabled: true
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
#defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
3.4.4、主启动类、业务类:直接从8001里copy即可
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @create 2021-01-17 18:47
*/
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8002 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8002.class,args);
}
}
3.4.5、修改8001/8002的controller
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @create 2020-12-08 17:02
*/
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
//增加端口号,用来区分负载均衡时,那一端口提供的服务
@Value("${server.port}")
private String serverPort;
//写用PostMapping
@PostMapping(value = "payment/create")
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("*****插入结果"+result);
if(result > 0){
return new CommonResult(200,"插入数据库成功,serverPort:"+serverPort,result);
}else{
return new CommonResult(444,"插入数据库失败",null);
}
}
//读用GetMapping
@GetMapping(value = "payment/get/{id}")
public CommonResult getpaymentByid(@PathVariable("id") Long id){
Payment payment = paymentService.getpaymentByid(id);
log.info("*****查询结果"+payment);
if(payment != null){
return new CommonResult(200,"查询成功,serverPort:"+serverPort,payment);
}else{
return new CommonResult(444,"没有对应记录,查询ID"+id,null);
}
}
}
3.4.6、负载均衡:此时,我们使用80端口的服务消费方来访问 CLOUD-PAYMENT-SERVICE 服务,输入网址http://localhost//consumer/payment/get/4,但是我们每次得到的数据都是:
也就是说每次访问的具体微服务都是8001端口的CLOUD-PAYMENT-SERVICE服务,这明显是不符合业务逻辑的,原因就是在消费方代码中我们将服务访问地址写死了,没有实现负载均衡,这显然是不对的,所以我们应该让80访问服务名,而不是具体的服务,同时在配置文件中通过 @LoadBalanced 注解赋予RestTemplate负载均衡能力,该负载均衡默认为轮询方式,所以将80服务的配置文件修改如下:
package com.atguigu.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* @className: ApplicationContextConfig
* @description:
* @author: liusCoding
* @create: 2020-06-04 11:57
*/
@Configuration
public class ApplicationContextConfig {
@Bean("restTemplate")
@LoadBalanced//使用该注解赋予RestTemplate负载均衡的能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
同时更改调用路径,这二者缺一不可f否则报错
package com.atguigu.springcloud.controller;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @create 2020-12-10 13:54
*/
@RestController
public class OrderController {
// 通过在eureka上注册过的微服务名称调用
public static String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult <Payment> create(Payment payment){
//写操作
return restTemplate.postForObject(PAYMENT_URL + "/payment/create",payment, CommonResult.class);
}
@GetMapping("/consumer/payment/get/{id}")
public CommonResult <Payment> getPayment(@PathVariable("id") Long id){
//读操作
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/"+id,CommonResult.class);
}
}
3.4.7、访问测试:http://localhost//consumer/payment/get/4,负载均衡效果达到,当然此时负载均衡我们还没有用到Ribbon,再Ribbon和Eureka整个后消费者可以直接调用服务而不用再关心地址和端口号,且该服务还有负载功能。
4、actuator微服务信息完善
4.1、主机名称:服务名称修改
当前问题:在注册中心显示的微服务中,我们发现服务名含有主机名称,这显然不是我们希望看到的
怎么能解决这个问题呢,只需要修改服务提供方(8001和8002)的配置文件,向其中的eureka部分加入即可配置该服务显示的服务名称
instance:
instance-id: payment8001
最终的整体配置文件如下:
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: com.mysql.jdbc.Driver # mysql驱动包
url: jdbc:mysql://192.168.3.3:3306/springcloud-2020?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: root
http: #解决输出中文信息到页面为乱码的问题
encoding:
charset: UTF-8
force: true
enabled: true
eureka:
instance:
instance-id: payment8001 #当前服务名称
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机版
#defaultZone: http://localhost:7001/eureka
# 集群版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
8002服务的修改同上,此时再访问注册中心,看到的服务具体名称中就没有主机名了,而是我们配置好的服务名称:
4.2、访问信息有IP信息提示
当前问题:我们在鼠标移动到具体服务时,提示的地址信息中并没有服务所在具体主机的IP地址,这在开发中不方便定位具体微服务。
解决方式仍然是通过配置文件,在配置文件中向其中的eureka部分加入即可配置该服务访问路径可以显示IP地址:
instance:
prefer-ip-address: true # 访问路径可以显示IP地址
最终的配置文件如下:
eureka:
instance:
instance-id: payment8002
prefer-ip-address: true # 访问路径可以显示IP地址
鼠标再次移动到该服务时,可以发现,已经提示了IP地址:
5、服务发现Discovery
对于注册进Eureka服务注册中心的微服务,可以通过服务发现来获取该服务的信息。
5.1.、修该微服务的Controller,向其中注入DiscoveryClient,并编写相应Controller方法
package cn.sher6j.springcloud.controller;
......
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
......
/**
* @author sher6j
*/
@RestController
@Slf4j
public class PaymentController {
.......
@Autowired
private DiscoveryClient discoveryClient;
.......
@GetMapping("/payment/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices(); //获取服务列表的信息
for (String service : services) {
log.info("=======service:" + service + "=======");
}
//根据微服务名称获取具体服务实例
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("=======" + instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri() + "=======");
}
return this.discoveryClient;
}
}
DiscoveryClient对象中的 getServices 方法用于获取服务列表的信息,也就是有哪些服务,如cloud-payment-service服务, getInstances 方法用于获取服务列表对应的具体服务实例,如cloud-payment-service服务对应的8001和8002服务。
5.2、修改主启动类
只需要在主启动类上添加注解@EnableDiscoveryClient,修改后的主启动类:
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @create 2020-12-07 16:58
*/
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
5.3、测试,http://localhost:8001/payment/discovery,我们可以看到获取的服务信息,即完成了服务发现:
后台也对服务列表进行了日志打印:
6、Eureka自我保护(CAP里面的AP分支)
6.1、自我保护机制
保护模式主要用于一组客户端和EurekaServer之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
如果在Eureka Server的首页看到以下提示,说明Eureka进入了保护模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
换句话说就是,某时刻某一个微服务不可用了,Eureka不会立刻清理,而是依旧会对该微服务的信息进行保存。
6.2、产生原因
6.2.1、为什么会产生Eureka自我保护机制???
为了防止 EurekaClient可以正常运行,但是与EurekaServer网络不通 情况下,EurekaServer不会立刻将EurekaClient服务剔除。
6.2.2、什么是自我保护模式?
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之前无法正常通信,以上行为可能变得非常危险——因为微服务本身是健康的,只是由于网络问题链接不到EurekaServer,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障,网络延时),那么这个节点就会进入自我保护模式。
在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例,宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
6.3、怎么禁止自我保护
6.3.1、在EurekaServer端修改配置文件即可设置关闭自我保护机制
eureka:
server:
# 关闭自我保护机制,保证不可用服务被及时剔除
enable-self-preservation: false
# 时间间隔
eviction-interval-time-in-ms: 2000
6.3.2、在EurekaClient端修改配置文件
eureka:
instance:
instance-id: payment8001
# Eureka客户单向服务端发送心跳的时间间隔,默然是30秒
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限,默然为90秒,超时将剔除服务
lease-expiration-duration-in-seconds: 2
这样就会使EurekaClient客户端的微服务很快死亡。