服务注册发现:Eureka快速搭建以及相关组件与配置说明

672 阅读6分钟

Eureka简介

Eureka是Netflix开源的一个服务注册发现工具,基于REST协议提供服务。也加入到Spring Cloud子项目中。本文介绍一下基于SpringBoot的Eureka快速使用,以及Eureka各个组件和相关配置的说明。

Eureka服务角色

每一个Eureka服务都是一个实例(instance)。而一个实例在Eureka中有两种角色:Eureka ServerEureka Client

  • Eureka Server:注册中心本身,负责监听和维护Eureka Client相关的信息。如主机的加入和退出等
  • Eureka Client:又分为两种,Service ProviderService Consumer
    • Service Provider:服务提供者,在Eureka Server上进行注册,续约,上下线等操作
    • Service Consumer:服务消费者,从Eureka Server上获取服务列表(会定期更新),以此发起调用

当然,这些角色都不是绝对的,只是一个逻辑上的分类,一个实例可以具备Provider和Service的双重身份

Eureka架构

Eureka简单使用

这边我就不打算打造单节点了,直接整一个伪集群。 先开一个SpringBoot项目,pom.xml里引入以下依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

同时启动类上加上@EnableEurekaServer注解:

@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }

}

再分别建立application-v1.properties,application-v2.properties,application-v3.properties 内容分别为:

spring.application.name=eureka-server
server.port=7001
eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://localhost:7002/eureka/,http://localhost:7003/eureka/
spring.application.name=eureka-server
server.port=7002
eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://localhost:7001/eureka/,http://localhost:7003/eureka/
spring.application.name=eureka-server
server.port=7003
eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://localhost:7001/eureka/,http://localhost:7002/eureka/

可以看到,区别也仅仅是端口,不同。比如对于7001端口来说,它作为Eureka Server,同时也是7002和7003端口上Eureka Server的Client,从而搭建出一个Eureka集群

项目打成jar包后,分别执行

java -jar eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=v1 &
java -jar eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=v2 &
java -jar eureka-0.0.1-SNAPSHOT.jar --spring.profiles.active=v3 &

启动项目,访问localhost:7001可以看到:

EUREKA-SERVER服务已经注册上去了,对应的节点有三个。那这样Eureka集群就已经搭建好了,当然这只是一个最简单的Demo

Eureka相关参数和流程

第一次注册

当Service Provider第一次向Eureka Server注册的时候,它会把自己的相关信息都发给Eureka Server,包括服务名,ip,端口等。Eureka Server接收到之后,将该信息写入到自己的缓存之中

Service Consumer会按照一定的频率从Eureka Server种拉去服务列表(如果是第一次拉取的话是全量获取,后续是增量获取),获取到服务列表后,用特定的方法(比如Ribbon用的就是轮询的方法来实现客户端的负载均衡)从服务列表种选取一个实例来发送请求

配置:

# 服务名,注册到Eureka Server上,客户端通过这个名字来获取服务列表
spring.application.name: eureka-service

eureka.client.serviceUrl.defaultZone=http://localhost:7002/eureka/,http://localhost:7003/eureka/
# 是否向Eureka Server注册自己
eureka.client.register-with-eureka: true
# 是否向Eureka Server获取注册信息
eureka.client.fetch-registry: true

心跳检测

Provider

Eureka Server通过心跳检测来得知Provider的实时状态,心跳检测默认进行频率是30秒。当Eureka Server收到心跳包后,就进行一次续约。如果对应的服务状态发生了变化(比如机器下线了,或者新加入了一台机器),就要把这个更新写到一个“租约变更队列”之中,供后续Comsumer来获取

那Eureka Server怎么知道一个实例是否下线了呢?如果Eureka Server在90秒的时间内没有收到一个实例的心跳包,那么就会认为实例已经下线了,把这个记录更新到”租约变更队列“中

其实Client的下线可以有两种情况,一种是正常下线,在下线之前,Client会主动通知Eureka Server,使得Eureka Server能及时得知此消息;另一种是异常下线,比如进程崩溃,宕机,网络异常等情况,这种情况,Eureka Server90秒内没有收到心跳包就认为该实例下线

# 心跳频率,用来续约,单位:秒
eureka.instance.lease-renewal-interval-in-seconds: 30
#  eureka server多久没有收到心跳,则表示对应的实例过期,单位:秒。
eureka.instance.lease-expiration-duration-in-seconds: : 90s

Consumer

Consumer和Eureka Server之间的通信主要是为了获取服务列表,以达到一致性。在Consumer第一次连接上Eureka Server的时候,会进行一次全量获取,后续会每隔30秒进行一次增量的获取,那增量获取的信息是从哪来的呢?还记得我们之前聊过的那个”租约变更队列“吗?实际上就是Eureka Server从队列中获取到的信息,然后进行同步

当然,在这个过程中,因为同步时间是30s,所以在30s中可能会出现信息不一致的情况。当然对于大多数的客户端来说,这个不一致带来的问题不会很大,因为重试功能是不可能没有的。但如果真的需要有更强的一致性的话,可以把这个时间缩短,但是同时也意味着Consumer的心态变得更加频繁了,由此可能会带来一些额外的网络开销,这是需要注意的。并且无论这个时间缩得多短,不一致性也是肯定会存在的。并且Eureka实现的是AP,而抛弃了C(强一致性),所以从这个方面来考虑,这个频率也没必要设置得太快

# 是否从Eureka-Server中获取服务实例注册信息,默认值为true
eureka.client.fetch-registry: true
# 从Eureka-Server拉取注册服务实例信息频率,默认:30 秒
eureka.client.registry-fetch-interval-seconds: 30 

# 是否禁用增量获取服务实例注册信息,设置为true后,每次都是全量获取
eureka.disableDelta: false

自我保护机制

考虑这种情况:Eureka Server和Provider之间的网络通信出现了问题,但Provider还正常运行着,也还能对Consumer提供服务。但是由于它发送的心跳包无法到达Eureka Server,Eureka Server认为它下线了,于是从服务列表中移除了这个服务,这样Consumer获取到新的服务列表之后,就会误以为Provider服务不可用,进而导致一些问题

自我保护机制就是为了解决这个问题。当一分钟内Eureka Server收到的心跳包少于一个阈值的时候,就会开启自我保护机制,在这个状态中,Eureka Server不会从服务列表中移除实例(所以这个列表可能会有一些过期的实例,还是照样发给了Consumer)。当收到的心跳包数量达到阈值后,才会退出自我保护状态。

#是否开启自我保护模式。
eureka.server.enable-self-preservation: false
#开启自我保护模式比例阈值,当收到心跳包占期望收到心跳包数量低于这个值,进入自我保护模式。
eureka.server.renewal-percent-threshold: 0.85