SpringCloud&alibaba学习笔记系列
该笔记仅作为个人学习使用。
第二章Eureka服务注册与发现
2.1Eureka基础知识
2.1.1服务治理
SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理。
在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理也比较复杂,所以需要使用服务治理,管理服务于服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
2.1.2服务注册与发现
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,他是服务注册中心。而系统中的其他微服务,使用Eureka的客户连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别称方式注册到注册中心。另一方(消费者|服务提供者),以该别称的方式去注册中心上货渠道世纪的服务通讯地址,然后在实现本地RPC远程调用框架设计思想:在于注册中心,因为使用注册中心管理每个服务于服务之间的依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中(存放服务地址相关信息(接口地址))。
下左图时Eureka系统架构,右图是Dubbo的架构,请对比:
2.1.3Eureka的两个组件
Eureka包含两个组件:Eureka Server和Eureka Client
-
Eureka Server:提供服务注册服务
各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
-
Eureka Client:通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robbin)负载均衡算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为20s)。如果Eureka Server再多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移出(默认90s)。
2.2单机Eureka构建步骤
2.2.1搭建EurekaServer服务注册中心
1)新建module
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>springcloud2020</artifactId>
<groupId>com.jzt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>com.jzt</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>
<version>1.18.14</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
</project>
3)yml文件
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false #表示是否将自己注册到注册中心
fetch-registry: false #表示自己就是注册中心,不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4)主启动
package com.jzt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* 功能描述:
*
* @Author: sj
* @Date: 2020/10/18 8:22
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain {
public static void main(String[] args) {
SpringApplication.run(EurekaMain.class, args);
}
}
5)测试
说明eurekaserver服务部署完毕。
2.2.2将支付微服务注册到eurekaserver中
1)添加对应依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)修改yml文件
eureka:
client:
register-with-eureka: true #表示将自己注册到eurekaserver上,默认为true
fetch-registry: true #是否从Eurekaserver抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
service-url:
defaultZone: http://localhost:7001/eureka
3)主启动添加注解
package com.jzt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* 主启动类
* @author sj
*/
@SpringBootApplication
@EnableEurekaClient //将该服务注册到eurekaserver作为client
public class SpringCloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudApplication.class, args);
}
}
4)测试
2.2.3将订单微服务注册到eurekaserver中
1)添加对应依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2)修改yml文件
eureka:
client:
register-with-eureka: true #表示将自己注册到eurekaserver上,默认为true
fetch-registry: true #是否从Eurekaserver抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
service-url:
defaultZone: http://localhost:7001/eureka
3)主启动添加注解
@SpringBootApplication
@EnableEurekaClient //将该服务注册到eurekaserver作为client
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
4)测试
2.3Eureka集群理论
问题:微服务RPC远程服务调用最核心的是什么?
高可用,试想你的注册中心只有一个only one,它出故障了那就呵呵了,会导致整个微服务环境不可用。
解决方法:
搭建Eureka注册中心集群,实现负载均衡+故障容错。
6.Eureka集环境构建
1)参考server7001新建cloud-eureka-server7002
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>springcloud2020</artifactId>
<groupId>com.jzt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7002</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>com.jzt</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>
<version>1.18.14</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
</project>
3)修改本地host文件
修改在C:\Windows\System32\drivers\etc下的host文件
#微服务测试
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
4)写yml,并修改eureka7001的yml配置
7002
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false #表示是否将自己注册到注册中心
fetch-registry: false #表示自己就是注册中心,不需要去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
7001
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false #表示是否将自己注册到注册中心
fetch-registry: false #表示自己就是注册中心,不需要去检索服务
service-url:
defaultZone: http://eureka7002.com:7002/eureka/
5)添加主启动类
package com.jzt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* 功能描述:
*
* @Author: sj
* @Date: 2020/10/18 18:22
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain {
public static void main(String[] args) {
SpringApplication.run(EurekaMain.class, args);
}
}
6)测试
7).将其他服务注册到eureka集群中
只需要修改yml配置文件即可:
eureka:
client:
register-with-eureka: true #表示将自己注册到eurekaserver上,默认为true
fetch-registry: true #是否从Eurekaserver抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
service-url:
# defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
1.支付服务集群配置
1)新建支付微服务8002
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>springcloud2020</artifactId>
<groupId>com.jzt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8002</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.jzt</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<!-- 添加这个依赖之后就可以创建一个web应用程序。starter poms部分可以引入所有需要在实际项目中使用的依赖。
spring-boot-starter-web依赖包含所有的spring-core, spring-web, spring-webmvc,嵌入的Tomcat server和其他web应用相关的库。 -->
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<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>
<version>1.18.14</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3)拷贝8001yml,并修改yml
修改内容如下:
server:
port: 8002
...
4)拷贝8001业务代码至8002
注意:需要在两个业务代码中加上一段代码:
@Value("${server.port}")
private String port;
在打印日志的时候带上端口号,这样我们就能知道当我们发送一个请求时,是哪个微服务提供的服务响应。
如:
return new CommonResult(200, "插入数据成功!,server port:"+port,result);
5)测试
6)修改订单微服务
在controller中在url改为服务名称
// public static final String PAYMENT_URI = "http://localhost:8001";//单机版
public static final String PAYMENT_URI = "http://CLOUD-PAYMENT-SERVICE";//集群版
在RestTemplete添加负载均衡功能:
@Bean
@LoadBalanced //开启负载均衡功能
public RestTemplate getRestTemplete(){
return new RestTemplate();
}
2.3actuator微服务信息完善
当前问题:
1)注册到Eureka上的微服务显示列表时含有主机名称,我们希望以实例名称来显示;
2)能够显示IP;
修改yml文件
添加instance实例名称,显示ip
eureka:
client:
register-with-eureka: true #表示将自己注册到eurekaserver上,默认为true
fetch-registry: true #是否从Eurekaserver抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
service-url:
# defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
instance:
instance-id: payment8001 #实例名称
prefer-ip-address: true #显示ip
2.4服务发现Discovery
对于注册到Eureka里面的微服务,可以通过服务发现来获得该服务的信息。
1)修改cloud-provider-payment8001的controller
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "/payment/getinstance")
public Object getServiceInstance(){
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;
}
2)在启动类上添加开启服务发现注解
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient //开启服务发现
public class SpringCloudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudApplication.class, args);
}
}
3)测试
访问http://localhost:8001/payment/getinstance
2.5Eureka自我保护机制
2.5.1现象概述
保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不在删除服务注册表中的数据,也就是不会注销任何微服务。
如果Eureka Server的首页看到下面这段提示,则说明Eureka进入了保护模式:
2.5.2导致原因
1、什么是自我保护机制
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网格分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变的非常危险了——因为微服务本其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式"来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
2、产生Eureka自我保护机制的原因
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除。
一句话:某时刻某个服务不可用了,Eureka不会立刻清理,依旧会对该服务信息进行保存。
自我保护模式中,Eureka Server会保护服务注册表中的信息,不在注销任何服务实例。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
5.5.3如何禁止自我保护机制
使用eureka.server.enable-self-preservation=false可以禁止自我保护模式。
1)修改8001的yml配置
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false #表示是否将自己注册到注册中心
fetch-registry: false #表示自己就是注册中心,不需要去检索服务
service-url:
defaultZone: http://eureka7002.com:7002/eureka/
server:
enable-self-preservation: false #关闭自我保护机制,保证服务不可用时被及时剔除
eviction-interval-timer-in-ms: 2000
2)修改8001的yml配置
添加心跳间隔等时限
eureka:
client:
register-with-eureka: true #表示将自己注册到eurekaserver上,默认为true
fetch-registry: true #是否从Eurekaserver抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true,才能配合ribbon使用负载均衡
service-url:
# defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
instance:
instance-id: payment8001 #实例名称
prefer-ip-address: true #显示ip
lease-renewal-interval-in-seconds: 1 #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是90秒)
lease-expiration-duration-in-seconds: 2 #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除
2)启动服务查看:
说明eureka的默认保护机制已经关闭。
3)启动8001微服务
当我们手动关闭8001微服务时:
发现8001的注册信息立马被清除了。