一句话总结
Eureka用于服务注册与发现。在多服务间的交互是复杂的,Eureka将注册在其上的服务按key|value存储,能实现负载均衡@loadBalanced以及容错处理——集群保证。
回顾
之前通过Rest风格中的RestTemplate实现了两个微服务——支付与订单间的通信。
Eureka服务注册与发现
服务与服务间的调用是n对n的关系——》复杂——》服务治理——》Eureka
Eureka是什么?
Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件,以实现中间层服务器的负载平衡和故障转移。
它主要包括两个组件:Eureka Server 和 Eureka Client
-
Eureka Client:一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)
-
Eureka Server:提供服务注册和发现的能力(通常就是微服务中的注册中心)
服务在Eureka上注册,然后每隔30秒发送心跳来更新它们的租约。如果客户端不能多次续订租约,那么它将在大约90秒内从服务器注册表中剔除。注册信息和更新被复制到集群中的所有eureka节点(防止宕机)。来自任何区域的客户端都可以查找注册表信息(每30秒发生一次)来定位它们的服务(可能在任何区域)并进行远程调用。
实例
- Eureka服节点多个,防止宕机。节点间的依赖关系是“互相注册,相互守望”。
- 1个服务的实现也有多个节点,可能存在大量访问请求。——负载均衡。
- 订单和支付两个微服务均在Eureka上注册,再负载均衡到具体的访问地址。
单机Eureka代码实现
Eureka也相当于是一个服务,那么也从下面6步着手:
- 新建Eureka模块
- 改pom.xml
- 建Yml(application.yml)
- 主启动
- 业务类
- 测试
一、 Eureka注册中心
1、新建cloud-eureka-server7001模块
pom.xml中加入依赖: ——要使用Eureka,当然首先得引入依赖
<dependencies>
<!--eureka-server-->
<dependency>
《! gva只需写ga。 Eureka为server !!!!!!!》
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--自定义api通用包-->
<dependency>
<groupId>org.xzq.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--boot web acctuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</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>
</dependencies>
2、resources目录下新建application.yml
《! 微服务的服务端口号必不可少,不然怎么访问localhost:70001/... 。 server.port》
server:
port: 7001
《! 这是真正和Eureka设置相关》
eureka:
instance:
hostname: localhsot #eureka服务端实例名称
client:
register-with-eureka: false #表示不像注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务
service-url:
《! 其实就是http://localhost:7001/eureka/ 服务注册与此目录下》
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3、编写启动类EurekaApplication7001
package com.xzq.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
《!主启动类@SpringBootApplication注解必不可少。 @EnableEurekaServer开启Server服务》
@SpringBootApplication
@EnableEurekaServer//开启EurekaServer
public class EurekaApplicatin7001 {
《!主启动类里面就注解和主函数入口。 mainboot快捷键。 参数填当前类.class》
public static void main(String[] args) {
SpringApplication.run(EurekaApplicatin7001.class, args);
}
}
二、支付微服务8001入驻7001
1、pom.xml添加
<!--eureka-server-->
<dependency>
《! 这里就是Eureka的client端啦》
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、改application.yml
eureka:
client:
register-with-eureka: true #表示向注册中心注册自己 默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
defaultZone: http://localhost:7001/eureka/ # 入驻地址
3、启动类加上注解@EnableEurekaClient
三、订单微服务80入驻7001
同上
Eureka集群代码实现
**原理说明**
服务注册:将服务信息注册到注册中心
服务发现:从注册中心获取服务信息
实质:存key服务名,取value调用地址
**步骤**
1. 先启动eureka注册中心
2. 启动服务提供者payment支付服务
3. 支付服务启动后,会把自身信息注册到eureka
4. 消费者order服务在需要调用接口时,使用服务别名去注册中心获取实际的远程调用地址
5. 消费者获得调用地址后,底层实际是调用httpclient技术实现远程调用
6. 消费者获得服务地址后会缓存在本地jvm中,默认每30秒更新异常服务调用地址
问题:微服务RPC远程调用最核心的是高可用,如果注册中心只有一个,出现故障就麻烦了。会导致整个服务环境不可用。
解决办法:搭建eureka注册中心集群,实现负载均衡+故障容错
互相注册,相互守望——宗旨
集群搭建步骤
1、依照7001新建7002,除了主启动类和yml配置文件改,其他都一样
2、修改C:\Windows\System32\drivers\etc下的hosts
末尾加上
# springcloud2020
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
3、修改7001项目 applicaton.yml
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端实例名称
client:
register-with-eureka: false #表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务
service-url:
《! 这就是相互注册》
defaultZone: http://eureka7002.com:7002/eureka/
4、修改7002(也需要相互注册)
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端实例名称
client:
register-with-eureka: false #表示不向注册中心注册自己
fetch-registry: false #false表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
5、eurekaserver集群效果
6、支付和订单两个微服务注册到eureka集群
修改80项目yml配置文件service-url:
#defaultZone: http://localhost:7001/eureka/ # 入驻地址
《!这里就是两个Eureka节点都要注册啦》
defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7001.com:7001/eureka/
7、8001同理
8、启动7001、7002再启动8001、80项目查看效果
搭建支付服务集群
1. 参照8001搭建8002服务
直接访问localhost:8001/payment/get/1
结果:{"code":200,"message":"查询数据成功,serverport:8001","data":{"id":1,"serial":"尚硅谷"}}
访问localhost:8002/payment/get/1
结果:{"code":200,"message":"查询数据成功,serverport:8002","data":{"id":1,"serial":"尚硅谷"}}
成功
****consumer访问时,第2个支付服务不起作用!!!****
访问localhost/**consumer**/payment/get/1
结果:{"code":200,"message":"查询数据成功,serverport:8001","data":{"id":1,"serial":"尚硅谷"}}
**但是会发现 ,每次范文都是8001端口**
原因是再80项目的controller层中,我们将请求路径写死了。
修改如下:
public class OrderController {
// private final static String PAYMENT_URL = "http://localhost:8001";
《!改为通过服务名称访问》
private final static String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
但是访问localhost/consumer/payment/get/1会出现500错误,原因是,****!!我们配置了以服务名的方式访问,但不能确定是哪一个服务。!!****
2. 我们需要给restTemplate开启负载均衡,默认是轮循。
《! 修改配置类》
@Configuration
public class ApplicationContextConfig {
@Bean
《! 开启》
@LoadBalanced//开启负载均衡
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
Eureka的自我保护机制
1. 为什么会产生自我保护机制?
为防止EurekaClient可以正常运行,但是与EurekaServer网络不通的情况下,EurekaServer**不会立刻将EurekaClient服务剔除**。
2. 什么是自我保护机制?
默认情况下,当Eureka server在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒).
但是,如果**短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制**。
比如在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server一起重启(因为在开发过程中不会修改eureka注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka管理界面看到Renews threshold和Renews(last min),当后者(最后一分钟收到的心跳数)小于前者(心跳阈值)的时候,触发保护机制,会出现红色的警告:
EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.
从警告中可以看到,eureka认为虽然收不到实例的心跳,但它认为实例还是健康的,eureka会保护这些实例,不会把它们从注册表中删掉。
在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。
综上,自我保护模式是一种应对网络异常的安全保护措施它的架构哲学是宁可同时保留所有微服务,也不忙盲目注销健康的微服务,使用自我保护模式,可以让Eureka集群更加健壮,稳定。——好死不如赖活着
隶属于CAP 的AP分支。
3. 如何禁止自我保护机制
注册中心配置yml:
server:
enable-self-preservation: false # 关闭自我保护机制 保证不可用服务及时清除
eviction-interval-timer-in-ms: 2000
服务提供者8001 yml文件配置:
lease-renewal-interval-in-seconds: 1 # eureka客户端向服务端发送心跳的时间间隔 单位秒 默认30
lease-expiration-duration-in-seconds: 2 # eureka