源码地址 https://github.com/coderTomato/mscloud_H
1. Eureka基础知识
1.1 什么是服务治理
SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理
在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册
1.2 什么是服务注册与发现
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到eureka Server并维持心跳连接。这样系统的维护人员就可以通过eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用,RPC远程调用的核心设计思想: 在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址的相关信息)
1.3 Eureka两组件
eureka包含两个组件: eureka server和eureka client
Eureka server提供服务注册服务
各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
EurekaClient通过注册中心进行访问
是一个java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的、使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期30秒)如果EurekaServer在
多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)
2.单机Eureka构建步骤
2.1 IDEA生成eurekaServer端服务注册中心
2.1.1 创建 cloud-eureka-server7001模块
2.1.2 修改pom文件
<dependencies>
<!-- eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包-->
<dependency>
<groupId>com.jd.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</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>
<!-- devtools-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
复制代码
2.1.3 编写YML文件
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
复制代码
2.1.4 修改主启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
复制代码
2.1.5 测试
2.2 EurekaClient端cloud-provider-payment8001注册进eurekaServer成为服务提供者
2.2.1 修改pom文件
springcloud1.x 使用如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
复制代码
springcloud2.x 添加如下依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
复制代码
2.2.2 修改yml文件 添加
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
service-url:
defaultZone: http://localhost:7001/eureka
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
复制代码
2.2.3 修改主启动类
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
复制代码
2.2.4 测试
先启动EurekaServer
微服务注册名配置说明
2.3 EurekaClient端cloud-consumer-order80注册进eurekaServer成为服务消费者
2.3.1 修改pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
复制代码
2.3.2 修改yml文件 添加
spring:
application:
name: cloud-order-service
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
service-url:
defaultZone: http://localhost:7001/eureka
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
复制代码
2.3.3 修改主启动类
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}
复制代码
2.3.4 测试
先启动EurekaServer 7701服务
再启动服务提供者provider8001服务
http://localhost/consumer/payment/get/7
服务可以正常访问
3.集群Eureka构建步骤
3.1 Eureka集群原理说明
微服务RPC远程服务调用最核心的是什么?
高可用,如果注册中心只有一个,它出故障了会导致整个微服务环境不可用,所以解决办法:搭建Eureka注册中心集群,实现负载均衡+故障容错
3.2 EurekaServer集群环境构建步骤
3.2.1 参考cloud-eureka-server7001新建cloud-eureka-server7002
3.2.2 修改pom文件
<dependencies>
<!-- eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包-->
<dependency>
<groupId>com.jd.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</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>
<!-- devtools-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
复制代码
3.2.3 修改映射配置(hosts文件)
win路径 C:\Windows\System32\drivers\etc\hosts
mac路径 /etc/hosts
hosts文件里添加如下配置
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
3.2.4 修改YML文件
7001的yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com
#hostname: localhost #eureka服务端的实例名称 单机版
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7002.com:7002/eureka/
复制代码
7002的yml
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com
#hostname: localhost #eureka服务端的实例名称 单机版
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
复制代码
3.2.5 主启动
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class, args);
}
}
复制代码
3.3 将支付服务8001微服务发布到Eureka集群配置中
只需要改yml文件
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
复制代码
3.4 将订单服务发布到Eureka集群配置中
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
复制代码
3.5 测试01
先要启动EurekaServer7001/7002服务
再启动服务提供者provider8001
最后启动消费者order80
eureka相互注册 说明集群搭建成功
3.6 支付服务提供者8001集群环境构建
3.6.1 参考cloud-provider-payment8001新建cloud-provider-payment8002
3.6.2 复制8001的pom文件到8002的pom
3.6.3 编写yml文件
只修改端口为8002其它都一样
3.6.4 修改主启动类
3.6.5 将8001的业务类直接复制到8002
3.6.6 修改8001/8002的Controller
添加端口
3.7负载均衡
3.7.1 订单服务访问地址不能写死
//public static final String PAYMENT_URL="http://localhost:8001";
//通过在eureka上注册过的微服务名称调用
public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";
3.7.2 使用@LoadBalanced赋予RestTemplate负载均衡能力
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced // 使用该注解赋予RestTemplate负载均衡能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
复制代码
3.8 测试02
先启动EurekaServer7001/7002
再启动服务提供者provider8001/8002
最后启动消费者order80
http://localhost/consumer/payment/get/7
结果负载均衡效果达到 8001/8002端口交替出现
Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号,且该服务还具有负载均衡功能
4.actuator微服务信息完善
4.1 主机名称 服务名称修改
在yml文件末尾添加instance-id
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
#defaultZone: http://localhost:7001/eureka
instance:
instance-id: payment8001
复制代码
4.2 访问信息有IP信息提示
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
instance:
instance-id: payment8002
prefer-ip-address: true #访问路径可以显示IP地址
复制代码
当指向payment8002时,左下角显示了ip
5. 服务发现Discovery
对于注册进eureka里面的微服务,可通过服务发现来获得该服务的信息
5.1 修改cloud-provider-payment8001的Controller 添加
@Resource
private DiscoveryClient client;
@GetMapping(value="/payment/discovery")
public Object discovery(){
List<String> services = client.getServices();
for (String ele : services) {
log.info("***ele:"+ele);
}
List<ServiceInstance> instances = client.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri());
}
return client;
}
复制代码
5.2 8001主启动类 添加@EnableDiscoveryClient注解
5.3 自测
http://localhost:8001/payment/discovery
6. eureka自我保护
6.1 故障现象
概述
保护模式主要用于一组客户端和EurekaServer之间存在网络分区场景下的保护。一旦进入保护模式EurekaServer将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务
如果在Eureka的首页看到以下这段提示,则说明Eureka进入了保护模式
6.2 导致原因
什么是自我保护模式?
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
一句话总结
某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存
6.3 怎么禁止自我保护
6.3.1注册中心eurekaserver7001修改
eureka:
instance:
hostname: eureka7001.com
client:
register-with-eureka: false #false表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
server:
#关闭自我保护机制,保证不可用服务被及时剔除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
复制代码
关闭效果
6.3.2 生产者客户端eurekaclient端8001修改
配置
eureka:
client: #客户端注册进eureka服务列表内
register-with-eureka: true #表示是否将自己注册进eurekaServer默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true 单节点无所谓,集群必须为true才能配合ribbon使用负载均衡
service-url:
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
defaultZone: http://localhost:7001/eureka
instance:
instance-id: payment8001
prefer-ip-address: true #访问路径可以显示IP地址
#Eureka客户端向服务端发送心跳的时间间隔,默认30秒
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,默认90秒 超时剔除服务
lease-expiration-duration-in-seconds: 2
复制代码
测试
先启动7001再启动8001
关闭8001, 服务马上被删除