前言
在微服务分布式的实际开发中,需要保证在发生故障时各组件的高可用。而Eureka的高可用就是通过进行集群部署,保证当某一台服务不可用时,会进行自动转移至可用的服务中。
在讲解Eureka集群前,先来看一下分布式中的CAP。
CAP
根据百度百科定义,CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
以下内容摘自百度百科:
-
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
-
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
-
分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
Eureka是满足AP
的:
- (P)分区容错性。因为在Eureka中,当某几个节点挂掉后并不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。
- (A)可用性。在向某个Eureka注册时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用,只不过查到的信息可能不是最新的(不保证强一致性)。
EurekaServer的高可用
在Eureka中,当某台EurekaServer宕机时,EurekaClient的请求会自动切换到新的EurekaServer节点,当宕机的服务器重新恢复后,Eureka会再次将其纳入到服务器集群管理之中,当节点开始接受客户端请求时,所有的操作都会进行replicateTopeer(节点间复制)操作,将请求复制到其他EurekaServer当前所知的所有节点中。简单来说,EurekaServer的高可用,实际上就是将自己也作为服务向其他服务注册中心进行注册,这样就可以形成一组相互注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。
Eureka服务器集群
由于是在同一台机器上模拟,所以需要修改本机hosts文件。
文件位置→C:\Windows\System32\drivers\etc\hosts
添加内容→127.0.0.1 localhost server1 server2 server3
1、首先创建三个SpringBoot-Eureka-Server项目,引入依赖并在启动类加上@enableEurekaServer注解。(可参照Eureka单击版进行创建)
2、修改(添加)三个项目的配置文件。
项目一的yml文件配置。
# 端口号
server:
port: 8001
spring:
application:
name: eurekaServer
eureka:
instance:
# 实例的主机名
hostname: server1
client:
#表示不向注册中心注册自己。由于该应用为注册中心,所以设置为false。
register-with-eureka: true
#表示不去检索其他服务。由于注册中心的职责是维护服务实例,它并不需要检索服务,所以设置为false
fetch-registry: true
serviceUrl:
#指定服务注册中心地址 这里直接指向了本服务
defaultZone: http://server2:8002/eureka,http://server3:8003/eureka
项目2的yml文件配置
# 端口号
server:
port: 8002
spring:
application:
name: eurekaServer
eureka:
instance:
# 实例的主机名
hostname: server2
client:
#表示不向注册中心注册自己。由于该应用为注册中心,所以设置为false。
register-with-eureka: true
#表示不去检索其他服务。由于注册中心的职责是维护服务实例,它并不需要检索服务,所以设置为false
fetch-registry: true
serviceUrl:
#指定服务注册中心地址 这里直接指向了本服务
defaultZone: http://server1:8001/eureka,http://server3:8003/eureka
项目3的yml文件配置
# 端口号
server:
port: 8003
spring:
application:
name: eurekaServer
eureka:
instance:
# 实例的主机名
hostname: server3
client:
#表示不向注册中心注册自己。由于该应用为注册中心,所以设置为false。
register-with-eureka: true
#表示不去检索其他服务。由于注册中心的职责是维护服务实例,它并不需要检索服务,所以设置为false
fetch-registry: true
serviceUrl:
#指定服务注册中心地址 这里直接指向了本服务
defaultZone: http://server1:8001/eureka,http://server2:8002/eureka
注意以下几点:
- 注意defaultZone属性,多个注册中心地址都指向其他所有注册中心地址进行结伴注册,多个地址以逗号分开。
- 去掉fetch-registry 与 register-with-eureka配置(默认值为true,或者设置为ture)
- 启动非最后一个注册中心时会报Cannot execute request on any known server的错误,暂时不管它,实际上eureka注册中心的ui界面是能打开的,比如说3个注册中心,启动前两个会报错,最后一个启动后就正常了。
- 所有注册中心的节点的spring.application.name必须保持一致。
启动成功后打开浏览器挨个访问。
Eureka客户端注册到集群
1、首先创建SpringBoot-Eureka-Client项目,引入依赖并在启动类加上@enableEurekaClient注解。(可参照Eureka单击版进行创建)
2、修改(添加)项目的配置文件。
spring:
application:
name: eurekaclient
#端口号
server:
port: 8005
eureka:
client:
serviceUrl:
#注册中心地址
defaultZone: http://server1:8001/eureka,http://server2:8002/eureka,http://server3:8003/eureka
instance:
#启用ip配置,这样在注册中心列表看见的就是IP+端口号
prefer-ip-address: true
#实例名称
instance-id: ${spring.cloud.client.ip-address}:${server.port}
启动成功后刷新注册中心UI页面。
Eureka高可用测试
1、新建一个名为客户端项目。pom依赖如下:
<!-- eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、修改(添加)yml文件
# 端口号
server:
port: 8888
spring:
application:
name: ClientConsumer
eureka:
client:
serviceUrl:
#注册中心地址
defaultZone: http://server1:8001/eureka/,http://server2:8002/eureka/,http://server3:8003/eureka/
instance:
#启用ip配置,这样在注册中心列表看见的就是IP+端口号
prefer-ip-address: true
#实例名称
instance-id: ${spring.cloud.client.ip-address}:${server.port}
3、在启动类添加@EnableDiscoveryClient注解,以及创建RestTemplate方法。
@EnableDiscoveryClient
@SpringBootApplication
public class SpringBootEurekaClientConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootEurekaClientConsumerApplication.class, args);
}
/**
* 使用@Bean和@LoadBalanced注解为添加restTemplate添加负载均衡能力。
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
4、编写一个控制类,使用restTemplate访问服务提供者。
@RestController
public class index {
@Autowired
private RestTemplate restTemplate;
/**
* 使用restTemplate调用服务提供者。地址中的IP是yml配置文件中spring.application.name的值
* @return
*/
@GetMapping("/")
public String index() {
return restTemplate.getForObject("http://eurekaClient/", String.class);
}
}
最后启动三个server,再启动服务提供者,最后在启动服务消费者。 当所有程序启动后。打开浏览器访问 http://localhost:8001 查看注册中心UI界面。可以看到服务提供者和消费者都已经注册到注册中心。
然后访问 http://localhost:8888 看到以下界面说明测试成功。
现在可以尝试停止其中一个甚至全部的Eureka Server
,再继续访问,可以看见服务还是可以调用的,但是要知道此时调用方是根据本地的缓存列表中直接获取地址的,而不是从注册服务中心,等待下次心跳机制时间到时,才会去进行拉取最新的服务列表的。
Eureka的心跳机制是指在应用启动后,节点们将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在90秒内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除。
推荐一篇心跳机制源码刨析文章,有兴趣的话可以看一下→eureka 心跳机制 源码解析
文尾
文章均为学习阶段记录笔记,若有不妥请留言指正。谢谢!