写在前面
该系列博客仅用于本人学习尚硅谷课程SpringCloud笔记,其中的错误在所难免,如有错误恳请指正。
官方源码地址:https://github.com/zzyybs/atguigu_spirngcloud2020
什么是SpringCloud
Spring Cloud是微服务一站式服务解决方案,微服务全家桶。它是微服务开发的主流技术栈。SpringCloud 和 SpringCloud Alibaba 目前是最主流的微服务框架组合。
Spring Cloud包含了许多功能强大的组件,例如服务注册与发现、负载均衡、断路器、配置管理、消息总线等,这些组件可以帮助开发者构建弹性、可靠、可扩展的分布式系统。
微服务是一种理念。程序员可以将应用程序拆分为多个微服务,每个微服务负责实现一个特定的功能,并通过Spring Cloud提供的组件进行协调和管理。这样,程序员可以更加灵活地组织和扩展应用程序,同时提高系统的可维护性和可靠性。
前期准备
父工程
首先创建一个父工程。maven版本使用3.5,不要使用idea自带的。
Java编译版本选择JDK8。
修改pom:找到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"><modelVersion>4.0.0</modelVersion><groupId>com.atguigu.springcloud</groupId><artifactId>cloud2020</artifactId><version>1.0-SNAPSHOT</version><!-- 统一管理jar包版本 --><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><junit.version>4.12</junit.version><log4j.version>1.2.17</log4j.version><lombok.version>1.16.18</lombok.version><mysql.version>5.1.47</mysql.version><druid.version>1.1.16</druid.version><mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version></properties><!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version --><dependencyManagement><dependencies><!--spring boot 2.2.2--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.2.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--spring cloud Hoxton.SR1--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR1</version><type>pom</type><scope>import</scope></dependency><!--spring cloud alibaba 2.1.0.RELEASE--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.spring.boot.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><optional>true</optional></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><addResources>true</addResources></configuration></plugin></plugins></build></project>
<properties></properties>
:后序需要创建子工程,在父亲工程这统一管理jar包。<dependencyManagement></dependencyManagement>
:通过该标签管理子模块的版本号。要注意的是,该标签只是声明了依赖,但是不是实现引入。如果要引入,需要将放到该标签外面,刷新等待引入后再放回该标签里面。<dependencies></dependencies>
dependencyManagement只是声明一个依赖,而不实现引入,故需要子模块中也需要对依赖进行声明,倘若不声明子模块自己的依赖,是不会从父模块中继承的;只有子模块中也声明了依赖。并且没有写对应的版本号它才会从父类中继承;并且version和scope都是取自父类;此外要是子模块中自己定义了自己的版本号,是不会继承自父类的。
里面的部分依赖并不是当前需要的,如果发现有的依赖导致了报错,可以先将相关依赖注释。
创建微服务 cloud-provider-payment8001
该微服务用于客户端服务的提供者。
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-provider-payment8001</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!--eureka-client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity 当前不需要,主要注释掉 --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</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><!--这个和web要写到一块--><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><!--mysql-connector-java--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</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>
yml
启动类
可以直接通过spring初始化一步到位。
常规操作
数据库建表
create table `payment`(`id` bigint(20) not null auto_increment comment 'ID',`serial` varchar(200) default '',PRIMARY KEY (`id`))ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8select * from payment;
数据可以随意添加两条。本人数据如下
entities
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;@Data //set/get方法
@AllArgsConstructor //有参构造器
@NoArgsConstructor //无参构造器
public class Payment implements Serializable {private long id;//数据库是bigintprivate String serial;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;//返回给前端的通用json数据串
@Data //set/get方法
@AllArgsConstructor //有参构造器
@NoArgsConstructor //无参构造器
public class CommonResult<T> {private Integer code;private String message;private T data; //泛型,对应类型的json数据//自定义两个参数的构造方法public CommonResult(Integer code, String message){this(code, message, null);}
}
dao
@Mapper
public interface PaymentDao {int create(Payment payment);Payment getPaymentById(@Param("id") Long id);
}
resource下创建mapper文件夹,新建PaymentMapper.xml。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.atguigu.springcloud.dao.PaymentDao"><resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment"><id column="id" property="id" jdbcType="BIGINT"/><id column="serial" property="serial" jdbcType="VARCHAR"/></resultMap><insert id="create" parameterType="com.atguigu.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">insert into payment(serial) values (#{serial})</insert><select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">select * from payment where id = #{id}</select>
</mapper>
Controller && Service
Service层
public interface PaymentService {int create(Payment payment);Payment getPaymentById(@Param("id") Long id);
}
@Service
public class PaymentServiceImpl implements PaymentService {@Autowiredprivate PaymentDao paymentDao;@Overridepublic int create(Payment payment) {return paymentDao.create(payment);}@Overridepublic Payment getPaymentById(Long id) {return paymentDao.getPaymentById(id);}
}
Controller层
@RestController
@Slf4j
public class PaymentController {@Resourceprivate PaymentService paymentService;@PostMapping(value = "/payment/create")// 注意这里的 @RequestBody 是必须要写的,虽然 MVC可以自动封装参数成为对象,// 但是当消费者项目调用,它传参是 payment 整个实例对象传过来的, 即Json数据,因此需要写这个注解public CommonResult<Integer> create(@RequestBody Payment payment) {int result = paymentService.create(payment);log.info("****插入结果:" + result);if (result > 0) {return new CommonResult<>(200, "插入数据库成功", result);}return new CommonResult<>(444, "插入数据库失败", null);}@GetMapping(value = "/payment/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {Payment result = paymentService.getPaymentById(id);log.info("****查询结果:" + result);if (result != null) {return new CommonResult<>(200, "查询成功", result);}return new CommonResult<>(444, "没有对应id的记录", null);}
}
目录结构如下
启动项目
找到启动类,然后点击运行启动。启动过程中出现了异常暂时不要管。打开浏览器,访问http://localhost:8001/payment/31(注意这里的31是本人的id数据)访问已经添加的数据。如果需要插入数据,可以使用postman传入Json。
创建模块 cloud-api-commons
后面的80需要和前面的8001相同的内容。为了方便管理,将相同的类放在该模块并进行打包。
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-api-commons</artifactId><dependencies><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><!-- hutool 工具包 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.1.0</version></dependency></dependencies>
</project>
将8001中entities包下的类复制到该模块,删除8001下的entities包。
等待成功后,找到8001,7001中的该依赖然后加载。
创建微服务 cloud-consumer-order80
该微服务用于客户端服务的消费者。
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-consumer-order80</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- <dependency><!– 引入自己定义的api通用包,可以使用Payment支付Entity –> --><!-- <groupId>com.atguigu.springcloud</groupId> --><!-- <artifactId>cloud-api-commons</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>
yml
server:port: 80 # 默认 80 端口,只需要输入网址即可eureka:client:service-url:defaultZone: http://localhost:7001/eureka# 将自己注册进去 trueregister-with-eureka: true#是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: truespring:application:name: cloud-order-service
controller && config
config
@Configuration
public class ApplicationContextConfig {// RestTemplate是Spring框架提供的一个用于发送HTTP请求的类。它简化了与RESTful服务的交互,可以方便地发送GET、POST、PUT、DELETE等请求,并且支持处理响应结果。@Beanpublic RestTemplate getRestTemplate(){return new RestTemplate();}
}
controller
@RestController
@Slf4j
public class OrderController {//远程调用的 地址public static final String PAYMENY_URL = "http://localhost:8001";@Resourceprivate RestTemplate restTemplate;@PostMapping("customer/payment/create")public CommonResult<Payment> create (Payment payment){return restTemplate.postForObject(PAYMENY_URL + "/payment/create",//请求地址payment,//请求参数CommonResult.class);//返回类型}@GetMapping("customer/payment/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id")Long id){return restTemplate.getForObject(PAYMENY_URL + "/payment/" + id,//请求地址CommonResult.class);//返回类型}
}
整个过程,通过浏览器调用order中的controller层,然后order80微服务发送http请求给payment8001微服务获取相关信息后返回。
到这里,所有的准备工作就完成了,接下来,进行eureka的正式使用。
Eureka
是什么
Eureka用于服务的注册与发现,用于管理和监控各个微服务。
比如,使用微服务后,不同的微服务在不同的机器上,为了简单方便管理,可以使用Eureka进行注册。
机制简介
Eureka包括两个组件:Eureka Server
和Eureka Client
。
- Eureka Server:服务器,里面有一个注册表,保存了不同的服务所在的机器和端口号。
- Eureka Client:客户端,负责将服务注册到Eureka Server中。
Eureka Client组件告诉Eureka Server自己在哪台机器上,监听着哪个端口;Eureka Client需要调用其他微服务的时候,通过Eureka Server寻找其他服务客户端,然后将这些相关信息从Eureka Server的注册表中缓存到自己的本地。
服务在Eureka上注册,然后定期发送心跳来更新它们的续约。如果客户端不能多次续订,那么它将在大约90秒内从服务器注册表中剔除。
服务提供者向注册中心注册服务,并每隔30秒发送一次心跳,如果Eureka长时间后还未收到服务提供者发来的心跳时,那么它就会认定该服务已经死亡就会注销这个服务。这里注销并不是立即注销,而是会在60秒以后对在这个之间段内“死亡”的服务集中注销,如果立即注销,势必会对Eureka造成极大的负担。这些时间参数都可以人为配置。
Eureka还有自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,所以不会再接收心跳,也不会删除服务。
客户端消费者会向注册中心拉取服务列表,因为一个服务器的承载量是有限的,所以同一个服务会部署在多个服务器上,每个服务器上的服务都会去注册中心注册服务,他们会有相同的服务名称但有不同的实例id,所以拉取的是服务列表。我们最终通过负载均衡来获取一个服务,这样可以均衡各个服务器上的服务。
使用Eureka
刚刚我们创建了一个微服务 cloud-provider-payment8001。当前的项目比较简单,管理起来不困难。但是如果项目比较多,而且分布在不同的机器上,管理就比较麻烦了,可以使用eureka进行服务的注册。现在将该微服务进行注册。
eureka有两个组件;server和client。将cloud-provider-payment8001作为client,那么,需要一个server,为此,需要再写一个微服务cloud-eureka-server7001,表示eureka的服务中心,端口号是7001。
按照上述方式,新建模块,选择maven工程。
创建微服务cloud-eureka-server7001
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><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-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-commons</artifactId> --><!-- <version>${project.version}</version> --><!-- </dependency> --><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --><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>
yml
server:port: 7001eureka:instance:hostname: localhost # eureka 服务端的实例名称client:# false 代表不向服务注册中心注册自己,因为它本身就是服务中心register-with-eureka: false# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:# 设置与 Eureka Server 交互的地址,查询服务 和 注册服务都依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
启动类
// exclude :启动时不启用 DataSource的自动配置检查
// 依赖中存在数据源,如果启动会提示找不到数据源
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer // 表示它是服务注册中心
public class EurekaServerMain7001 {public static void main(String[] args){SpringApplication.run(EurekaServerMain7001.class, args);}
}
启动类中需要格外注意的一个注解@EnableEurekaServer
,用于在Spring Boot应用程序中启用Eureka服务器。通过使用@EnableEurekaServer注解,我们可以将 cloud-eureka-server7001 标记为Eureka服务器,以便其他微服务可以进行注册和发现。
服务中心有了,使用@EnableEurekaClient
注解在 cloud-provider-payment8001 的启动类上。通过@EnableEurekaClient
可以将微服务标记为Eureka客户端,以便注册到Eureka服务器。同时要配置8001的yml。
server:port: 8001spring:application:name: cloud-payment-service # 项目名,也是注册的名字datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: org.gjt.mm.mysql.Driverurl: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: 123456
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.dkf.springcloud.entities # 所有Entity 别名类所在包eureka:client:# 注册进 Eureka 的服务中心register-with-eureka: true# 检索 服务中心 的其它服务fetch-registry: trueservice-url:# 设置与 Eureka Server 交互的地址defaultZone: http://localhost:7001/eureka/
启动该微服务,访问。
启动 cloud-provider-payment8001,cloud-consumer-order80
刷新7001网页,可以看到新注册了两个微服务。
现在看这两个微服务后面的状态信息。我们想要知道该微服务来自哪个ip,来自哪个机器,可以进行配置来显示。
微服务信息完善
order80和payment8001分别修改yml,添加
eureka:client:register-with-eureka: truefetch-registry: trueservice-url:defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/# 新增部分instance: instance-id: payment8001 # 提供者的idprefer-ip-address: true # 显示ip地址
就可以显示提供者的id和ip地址。
微服务发现Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。
先在8001的主启动类上添加@EnableDiscoveryClient
,然后添加代码。
@Resource
private DiscoveryClient discoveryClient;@GetMapping("/customer/discovery")
public Object discovery(){//获得服务清单列表List<String> services = discoveryClient.getServices();for(String service: services){log.info("*****service: " + service);}// 根据具体服务进一步获得该微服务的信息List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-ORDER-SERVICE");for(ServiceInstance serviceInstance:instances){log.info(serviceInstance.getServiceId() + "\t" + serviceInstance.getHost()+ "\t" + serviceInstance.getPort() + "\t" + serviceInstance.getUri());}return this.discoveryClient;
}
Eureka自我保护
看到该信息,说明eureka进入了自我保护。为了防止Eureka Client可以正常运行但是与Eureka Server网络不通情况下,Eureka Server不会立刻将Eureka Client服务剔除。
保护模式主要用于一组客户和Eureka Server之间存在网络分区场景下保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中固定信息,也就是不会注销任何微服务。
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时、卡顿、拥挤)时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过"自我保护模式"来解决这个问题—当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
自我保护模式是一种应对网络异常的安全保护措施。设计理念是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
禁止使用自我保护
修改yml。
server:
eureka:instance:hostname: eureka7001.com # eureka 服务端的实例名称client:# false 代表不向服务注册中心注册自己,因为它本身就是服务中心register-with-eureka: false# false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务fetch-registry: falseservice-url:defaultZone: http://localhost:7001/eureka/
# server:
# # 关闭自我保护机制,保证不可用该服务被及时剔除
# enable-self-preservation: false
# # eureka server清理无效节点的时间间隔
# eviction-interval-timer-in-ms: 2000
client:
eureka:client:service-url:defaultZone: http://localhost:7001/eureka# 将自己注册进去 trueregister-with-eureka: true#是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueinstance:instance-id: payment8001 # 提供者的idprefer-ip-address: true # 显示ip地址# Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30sleast-renewal-interval-in-seconds: 1# Eureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务least-expiration-duration-in-seconds: 2