Eureka是什么
Eureka是Netflix的一个子模块,也是核心模块之一。 Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。
Netflix在设计Eureka时遵守的是AP原则( 可用性Availability、 分区容错性Partition tolerance)
原理
基本架构
SpringCloud封装了Netflix公司开发的Eureka模块来实现服务注册和发现(请对比Zookeeper)。
Eureka采用了C-S的设计架构。Eureka Server作为服务注册功能的服务器,它是服务注册中心。
而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul) 就可以通过Eureka Server来发现系统中的其他微服务,并执行相关的逻辑。
Eureka包含两个组件:Eureka Server和Eureka Client
Eureka Server提供服务注册服务
各个节点启动后,会在EurekaServer中进行注册, 这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。EurekaClient是一个Java客户端
用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接
收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)。
三大角色
- Eureka Server提供服务注册和发现
- Service Provider服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到
- Service Consumer服务消费方从Eureka获取注册服务列表,从而能够消费服务
构建步骤
eureka服务注册中心Module
【microservicecloud-eureka-7001】
application.yml
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka 服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。只有客户端才向Eureka进行注册
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
启动类
在启动类上加@EnableEurekaServer
注解,表示为EurekaServer服务器端,接受其它微服务注册进来。
启动成功后访问localhost:7001便可看见Eureka的界面。
将已有的部门微服务注册进eureka服务中心
将microservicecloud-provider-dept-8001 注册进 microservicecloud-eureka-7001
provider8001的pom
<!-- 新增以下依赖 -->
<!-- 将微服务provider注册进Eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
provider8001的application.yml
# 追加以下内容
eureka:
client: #客户端注册进Eureka服务列表内#
service-url:
defaultZone: http://localhost:7001/eureka
以上defaultZone的配置,取自Eureka7001的application中的defaultZone的配置:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
这是Eureka7001设置的,与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
provider8001的启动类
增加@EnableEurekaClient
注解,本服务启动后会自动注册进Eureka服务中
启动
先启动服务端Eureka7001的服务,再启动客户端provider8001的服务,访问localhost:7001
该处的服务名取自provider8001的application.yml中配置的:
spring:
application:
name: microservicecloud-dept #对外暴露的微服务的名字
actuator与注册微服务信息完善
主机名:服务名称修改
DESKTOP-S98DNUG:microservicecloud-dept:8001 是入驻Eureka里的标识id,要把它换个别名
修改provider8001的application.yml
eureka:
instance:
instance-id: microservicecloud-dept8001
重启Eureka7001和provider8001,可发现标识id变为microservicecloud-dept8001
访问信息有ip地址提示
鼠标指向标识id时,让浏览器左下角显示服务ip
修改provider8001的application.yml
eureka:
instance:
prefer-ip-address: true #访问路径可以显示ip地址
重启后可显示ip
微服务info内容详细信息
点击标识id的超链接后 报告ErrorPage
provider8001的pom
<!-- 添加以下依赖 -->
<!-- actuator监控信息完善 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
总的父工程microservicecloud修改pom.xml添加构建build信息
<build>
<finalName>microservicecloud</finalName><!--父工程名字-->
<resources>
<resource>
<directory>src/main/resources</directory><!--允许访问所有工程里这个路径下的内容-->
<filtering>true</filtering><!--过滤开启-->
</resource>
</resources>
<plugins>
<plugin>
<!--负责解析和解读的插件-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<!--以$开头和以$结尾的 在src/main/resources路径下的配置文件信息 可以读取-->
<configuration>
<delimiters>
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
provider8001的application.yml
info:
app.name: microservicecloud-provider-8001
company.name: www.demo.com
build.artifactId: $project.artifactId$
build.version: $project.version$
点击标识id可以看到
eureka自我保护
某时刻某一个微服务不可用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存
什么是自我保护模式
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。
综上,自我保护模式是一种应对网络异常的安全保护措施。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false禁用自我保护模式。
服务发现Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
provider8001的DeptController
//添加以下内容
import org.springframework.cloud.client.discovery.DiscoveryClient;
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping(value="/dept/discovery", method=RequestMethod.GET)
public Object discovery(){
//获取所有服务
List<String> list = discoveryClient.getServices();
System.out.println("*********" + list);
//找到名称为MICROSERVICECLOUD-DEPT的服务,打印它的相关信息
List<ServiceInstance> srvList = discoveryClient.getInstances("MICROSERVICECLOUD-DEPT");
for(ServiceInstance element : srvList){
System.out.println(element.getServiceId() + "\t" + element.getHost()
+ "\t" + element.getPort() + "\t" + element.getUri());
}
return this.discoveryClient;
}
provider8001的启动类
增加@EnableDiscoveryClient
注解,做服务发现
启动
consumer80工程的DeptController_Consumer
//测试@EnableDiscoveryClient,消费端可以调用服务发现
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/discovery", Object.class);
}
启动,访问localhost:80/consumer/dept/discovery可以看到相关信息。
集群配置
pom文件
新建模块microservicecloud-eureka-7002和microservicecloud-eureka-7003,在各自的pom文件中引入和7001相同的依赖
<dependencies>
<!--eureka-server服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!--修改后立即生效,热部署-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
启动类
为Eureka7002和Eureka7003建启动类,与7001相同
package com.demo.springCloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //EurekaServer服务器端启动类,接受其它微服务注册进来
public class EurekaServer7002_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7002_App.class, args);
}
}
修改映射配置
修改hosts文件
C:\Windows\System32\drivers\etc路径下的hosts文件,新增如下内容:
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
三台Eureka服务器的yml配置
7001修改eureka.instance.hostname和client.service-url.defaultZone;7002与7003要修改端口号、hostname、defalutZone配置成除了自身之外的另外两个
server:
port: 7001
eureka:
instance:
hostname: euraka7001.com
# 单机版 hostname: localhost #eureka 服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己。只有客户端才向Eureka进行注册
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
# 单机版 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
provider8001发布到上面三台Eureka集群的配置中
修改provider8001的application.yml
eureka:
client: #客户端注册进Eureka服务列表内
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
# defaultZone: http://localhost:7001/eureka
启动
访问http://eureka7002.com:7002/可以看到相关信息
Eureka和Zookeeper
Zookeeper遵守CP
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。 但是zk会出现这样-种情况, 当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s,且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。
Eureka保证AP
Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一 致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
- Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
- Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
- 当网络稳定时,当前实例新的注册信息会被同步到其它节点中。
因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。