SpringCloud-Eureka
Eureka
注:Eureka中各个节点都是平等的,没有
ZK
中角色的概念,即使N-1个节点挂掉也不会影响其他节点的正常运行。
虽然Eureka已经停止维护了,但是并不代表我们不去学习它,理解它的思想也是后来为学习其他注册中心打下基础。
以下所有Demo都是基于上述入门案例改编。
服务调用出现的问题
- 服务消费者该如何获取服务提供者的地址信息?
- 如果有多个服务提供者,消费者该如何选择?
- 消费者如何得知服务提供者的健康状态?
服务治理
Spring Cloud
封装NetFlix
公司开发的Eureka
模块来实现服务治理
那么什么事服务治理呢?
当服务较少的时候,可能我们根本不需要什么所谓的服务治理,会觉得这不就是中间商赚差价吗,为什么我能直接调用还要再中间加个服务治理呢?其实啊在传统的RPC
框架中当服务多到一定程度时,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间的依赖关系,可以实现服务调用,负载均衡,熔断等,实现服务的注册与发现。
服务注册/发现
Eureka
采用了C/S
的设计架构,Eureka Server
作为服务注册功能的服务器,他是服务注册中心。而系统中的其他微服务,使用Eureka
的客户端连接到Eureka Server
并维持心跳连接。这样系统的维护人员就可以通过Eureka Server
来监控系统中各个微服务是否可以正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己的信息比如服务地址通讯地址等以别名的方式注册到注册中心上。另一方(消费者服务的提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址(ip
地址),然后在实现本地RPC
调用RPC
远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与每个服务之间的依赖关系(服务治理概念)。在任何RPC
远程调用框架中,都会有一个注册中心存放服务地址相关信息(接口地址)。
注册中心会维护所有注册到注册中心上的健康的服务的信息,当有消费者消费对应服务时,注册中心会返回服务的ip
地址等信息,消费者在通过这些信息去远程调用服务。
8001、8003宕机后,注册中心通过心跳检测,会将这些服务信息剔除。
Eureka组件
前面我们了解到,Eureka
是C/S
结构的,它有两个组件 Eureka Server
和 EurekaClient
Eureka Server
提供服务注册服务,就是我们所说的Eureka
的服务端,提供服务治理的相关功能。
各个微服务节点通过配置启动后,会在Eureka Server
中进行注册,这样Eureka Server
中的服务注册表中将会存储所有可用的服务节点的信息,服务节点的信息可用在界面中直观的看到。
Eureka Client
通过注册中心进行访问,Eureka
的客户端,提供了与Eureka
服务端交互的功能。
他是一个Java客户端,用于简化与Eureka Server
的交互,客户端同时也具备一个内置的,使用轮询(round-robin
)负载均衡算法的负载均衡器(用于同一个服务下多个提供者的情况),在应用启动后,将会
向Eureka Server
发送心跳(默认周期30秒)。如果Eureka Server
在多个心跳周期内没有接收到某个节点的心跳,Eureka Server
将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka常用配置
Eureka Server
Eureka Server
配置参数的格式:eureka.server.xxx
。
enable-self-preservation
:- 表示注册中心是否开启服务的自我保护能力(后面会介绍)。
renewal-percent-threshold
:- 表示 Eureka Server 开启自我保护的系数,默认:0.85。
eviction-interval-timer-in-ms
:- 表示
Eureka Server
清理无效节点的频率,默认 60000 毫秒(60 秒)。
- 表示
Eureka Instance
Eureka Instance
的配置参数格式:eureka.instance.xxx
。
instance-id
:- 表示实例在注册中心注册的唯一ID。
prefer-ip-address
:true
:实例以IP
的形式注册false
:实例以机器HOSTNAME
形式注册
lease-expiration-duration-in-seconds
:- 表示
Eureka Server
在接收到上一个心跳之后等待下一个心跳的秒数(默认 90 秒),若不能在指定时间内收到心跳,则移除此实例,并禁止此实例的流量。 - 此值设置太长,即使实例不存在,流量也能路由到该实例
- 此值设置太小,由于网络故障,实例会被取消流量
- 需要设置为至少高于
lease-renewal-interval-in-seconds
的值,不然会被误移除了。
- 表示
lease-renewal-interval-in-seconds
:- 表示
Eureka Client
向Eureka Server
发送心跳的频率(默认 30 秒),如果在lease-expiration-duration-in-seconds
指定的时间内未收到心跳,则移除该实例。
- 表示
Eureka Client
Eureka Client 的配置参数格式:eureka.client.xxx
。
register-with-eureka
:- 表示此实例是否注册到 Eureka Server 以供其他实例发现。在某些情况下,如果你不想自己的实例被发现,而只想发现其他实例,配置为 false 即可。
fetch-registry
:- 表示客户端是否从 Eureka Server 获取实例注册信息。
serviceUrl.defaultZone
:- 表示客户端需要注册的 Eureka Server 的地址。
用到的其他参数
spring.application.name
:- 表示应用名称,在注册中心中显示的服务注册名称。
spring.cloud.client.ip-address
:- 获取客户端的
IP
地址。
- 获取客户端的
上面讲的 Eureka 某些参数都可以可以在 Eureka 控制台上面找到
Eureka 控制台上面的其他参数都可以定制。
Eureka详细配置:Eureka详细配置
搭建一个Eureka 服务端
根据前文我们可以知道要搭建一个Eureka
服务器,需要用到Eureka Server
父工程的话pom.xml
与上述入门案例一致。
创建Eureka服务端工程Cloud-eureka-server7001
项目结构:
pom.xml
<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>Cloud-02-Eureka</artifactId>
<groupId>com.dyw</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>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<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>
</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.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>com.dyw</groupId>
<artifactId>Cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>application.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/创建启动类
//表示该模块为Eureka的注册中心
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}需要在启动类的头上加上
@EnableEurekaServer
注解,表示该模块为Eureka服务端。启动
启动后访问yml中的
http://${eureka.instance.hostname}:${server.port}/
地址看到如下界面表示成功。上述便是单机版Eureka注册中心的搭建了
支付微服务8001注册到Eureka Server中
将入门案例中的
Cloud-provide-payment-8001
复制粘贴到Eureka工程中并改名为Cloud-eureka-provider-payment8001
业务部分不用更改 主要是pom.xml
和application.yml
的修改改
pom.xml
新增依赖spring-cloud-starter-netflix-eureka-client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>改
application.yml
新增Eureka配置eureka:
client:
#表示是否将自己注册进EurekaServer 默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true.单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #要注册到的注册中心的地址
instance:
instance-id: payment8001 #指定实例名称
prefer-ip-address: true #是否显示ip启动类修改
//添加该注解提供与客户端的交互 这里是将服务注册到注册中心
public class PaymentMain8002 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8002.class,args);
}
}启动测试
可以通过
Eureka DashBoard
发现服务已经注册进了注册中心,实例的名称也是我们yml中指定的,服务名则是我们spring.application.name
。
订单微服务80入驻进Eureka Server中
将入门案例中的Cloud-consumer-order80
复制到Eureka工程中,改名为Cloud-eureka-consumer-order80
我们要做的也是修改pom.xml
和application.yml
修改
pom.xml
添加spring-cloud-starter-netflix-eureka-client
依赖<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>修改
application.yml
添加Eureka相关配置eureka:
client:
#表示是否将自己注册进EurekaServer 默认为true
register-with-eureka: false
#是否从EurekaServer抓取已有的注册信息,默认为true.单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
instance:
instance-id: order80 #指定实例id 不指定注册中心中显示的就是ip的格式启动类
//添加该注解提供与客户端的交互 这里是消费注册中心中的服务
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class, args);
}
}修改业务类
Controller
注册到注册中心上的服务,需要使用服务提供者注册到注册中心的服务名称代替
ip地址:端口
的方式调用。单个提供者时,使用真实ip地址:端口
与使用服务名称是没有区别的,但是当服务提供者是以集群的方式提供服务,那么这是想要使用负载均衡功能时,就必须使用这种方式了。均衡算法会返回一个正确ip:端口
。OrderController
// private static final String PAYMENT_URL = "http://localhost:8001";
private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";这里配置成服务名称其实也是一种规范,从一开始我们就提到了 约定 > 配置 > 编码
启动测试
GET : http://localhost:80/consumer/payment/get/1547118279208656900
{
"code": 200,
"msg": "查询成功",
"data": {
"id": 1547118279208656900,
"serial": "10"
}
}
Eureka集群原理说明
Eureka 集群,实际上就是启动多个 Eureka 实例,多个 Eureka 实例之间,互相注册,互相同步数据,共同组成一个 Eureka 集群。
得到8个字互相注册,相互守望。
问题:微服务RPC
远程服务调用最核心的是什么?
高可用,试想你的注册中心只有一个only one,万一它出故障了,会导致整个为服务环境不可用。
解决办法:搭建Eureka注册中心集群,实现负载均衡+故障容错。
搭建Eureka集群
本地机为了演示Eureka集群 需要修改电脑的hosts文件
原理我们已经直到,就是需要再搭建一个Eureka注册中心Cloud-eureka-server7002
,让我们原来搭建的Eureka注册中心和现在这个相互注册,使其相互同步数据。
搭建步骤这里不再演示只说这里需要更改的地方
Cloud-eureka-server7001
application.yml
server: |
Cloud-eureka-server7002
application.yml
server: |
启动后观看Eureka Dashboard
http://eureka7001.com:7001/
http://eureka7002.com:7002/
可用发现两个注册中心的DS Replicas
出现了对方的注册的实例名称,说明集群搭建成功。
这里我们启动Cloud-eureka-provider-payment8001
使其eureka7001.com
对应的注册中心上。
http://eureka7002.com:7002/
http://eureka7001.com:7001/
可用发现http://eureka7002.com:7002/
上同样出现了我们注册的服务。这就是集群,集群的各个节点之间相互同步信息,防止单一节点宕机的问题。
支付微服务集群配置
方式一
在实际开发中,不仅需要防止注册中心的单一节点宕机问题,服务提供者同样需要,不仅仅是为了防止宕机,同样也是为了提升服务的性能,服务提供者的集群不需要相互同步之间的信息,而是需要避免单一节点承受不住大量请求,导致反应慢或是请求失败等情况,同一服务新增节点集群 搭配上负载均衡,可以提升性能提高用户体验。
与Eureka搭建集群相似,没有什么特殊的改变,就是简单创建一个与之前服务相同工程Cloud-eureka-provider-payment8002
修改部分application.yml
server: |
方式二
另外,我们可以将**Cloud-eureka-provider-payment8001
**多次启动, 模拟多实例部署,但为了避免端口冲突,需要修改端口设置:
启动Cloud-eureka-provider-payment8002
和Cloud-eureka-provider-payment8001
以及Eureka注册中心。
可以发现同一个服务名称下面出现了两个服务实例,这也正是我们所配置的名称。
测试
注意: 当服务以集群出现时如果采用了用服务名称代替ip
+端口的格式的话 需要在RestTemplate
配置类下配置@LoadBalanced
实现负载均衡 否则会出现访问报错
RestTemplateConfig
|
并且为了方便查看负载均衡,我们在Controller的返回结果中加上了他们各自的端口
private final Integer serverPort = 8002; //Cloud-eureka-provider-payment8002 |
访问接口 POST : http://localhost:80/consumer/payment/create
{ |
{ |
DiscoveryClient
对于注册进eureka里面的微服务,可以通过DiscoveryClient
来获得该服务的信息
DiscoveryClient
提供了获取注册中心中注册服务信息的API
使用
修改Cloud-eureka-provider-payment8002
的Controller
新增
|
启动类新增注解@EnableDiscoveryClient
|
启动测试
GET : http://localhost:8002/payment/discovery
{ |
控制台:
Eureka自我保护机制
概述
保护模式主要用于一组客户端和Eureka Server之间存在网络分区(由于网络波动等原因引起)场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
官方对于自我保护机制的定义
自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
自我保护机制的工作机制
自我保护机制的工作机制是:如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,此时会出现以下几种情况:
- Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
- Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
- 当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
因此Eureka Server
可以很好的应对因网络故障导致部分节点失联的情况,而不会像ZK
那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。
为什么会产生Eureka自我保护机制?
该功能防止节点因为网络波动导致心跳检测信息不能及时发送到注册中心,但节点本身没有问题的情况。如果关闭了自我保护机制,一旦检测到某个节点没有在指定时间内发送心跳包,就会将该节点剔除。
如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式:
从这个机制可以看出Eureka满足了CAP理论中的AP分支。即达到了100%可用性和100%分区容错性。
什么是自我保护机制?
默认情况下,如果EurekaServer
在一定时间内没有接收到某个微服务实例的心跳,EurekaServer
将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer
之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka
通过“自我保护模式”来解决这个问题——当EurekaServer
节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
自我保护机制∶默认情况下EurekaClient
定时向EurekaServer
端发送心跳包,如果Eureka在server端在一定时间内(默认90秒)没有收到EurekaClient
发送心跳包,便会直接从服务注册列表中剔除该服务,但是在短时间( 90秒中)内丢失了大量的服务实例心跳,这时候Eurekaserver
会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通但是EurekaClient
为出现宕机,此时如果换做别的注册中心如果一定时间内没有收到心跳会将剔除该服务,这样就出现了严重失误,因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的)。也正如官方所说的使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
自我保护开关
Eureka自我保护机制,通过配置 eureka.server.enable-self-preservation
来true
打开/false
禁用自我保护机制,默认打开状态,建议生产环境打开此配置。
如果要实现服务失效自动移除,只需要修改以下配置
1、 注册中心关闭自我保护机制,修改检查失效服务的时间。
eureka: |
2、 微服务修改减短服务心跳的时间。
# 默认90秒 |
以上配置建议在生产环境使用默认的时间配置。
根据如上我们可以根据需求关闭注册中心的自我保护机制。
Cloud-eureka-server7001
application.yml
server: |
Cloud-eureka-provider-payment8002
application.yml
server: |
启动Cloud-eureka-server7001
和Cloud-eureka-provider-payment8002
界面中会出现这么一句话
表示自我保护机制以及关闭
此时关闭Cloud-eureka-provider-payment8002
Eureka会立刻剔除该服务。
Eureka停更说明
Eureka 2.0 (Discontinued)
The existing open source work on eureka 2.0 is discontinued. The code base and artifacts that were released as part of the existing repository of work on the 2.x branch is considered use at your own risk.
Eureka 1.x is a core part of Netflix’s service discovery system and is still an active project.
虽然Eureka停更了,但是Spring Cloud
也有着许多其他功能更为丰富更为优秀的服务治理组件。