4.0.3

该项目通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习惯用法,为 Spring Boot 应用程序提供 Netflix OSS 集成。通过一些简单的注释,您可以快速启用和配置应用程序内的常见模式,并使用经过考验的 Netflix 组件构建大型分布式系统。提供的模式包括服务发现(Eureka)。

1.服务发现:Eureka客户端

服务发现是基于微服务的架构的关键原则之一。尝试手动配置每个客户端或某种形式的约定可能很难做到,而且可能很脆弱。Eureka 是 Netflix 服务发现服务器和客户端。服务器可以配置和部署为高可用性,每个服务器将有关注册服务的状态复制到其他服务器。

1.1. 如何包含 Eureka 客户端

要将 Eureka 客户端包含在您的项目中,请使用组 ID 为org.springframework.cloud、工件 ID 为 的 启动程序spring-cloud-starter-netflix-eureka-client。有关使用当前 Spring Cloud 发布系列设置构建系统的详细信息,请参阅Spring Cloud 项目页面。

1.2. 向尤里卡注册

当客户端向 Eureka 注册时,它会提供有关自身的元数据,例如主机、端口、运行状况指示器 URL、主页和其他详细信息。Eureka 从属于服务的每个实例接收心跳消息。如果心跳在可配置的时间表内发生故障,则通常会从注册表中删除该实例。

以下示例显示了一个最小的 Eureka 客户端应用程序:

@SpringBootApplication
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

请注意,前面的示例显示了一个普通的Spring Boot应用程序。通过spring-cloud-starter-netflix-eureka-client在类路径上,您的应用程序会自动向 Eureka 服务器注册。需要配置来定位Eureka服务器,如下例所示:

应用程序.yml
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

在前面的示例中,defaultZone是一个神奇的字符串后备值,它为任何不表达首选项的客户端提供服务 URL(换句话说,它是一个有用的默认值)。

defaultZone属性区分大小写,并且需要驼峰式大小写,因为该serviceUrl属性是Map<String, String>. 因此,该defaultZone属性不遵循正常的 Spring Boot 蛇形命名约定default-zone

默认应用程序名称(即服务 ID)、虚拟主机和非安全端口(取自Environment)分别为${spring.application.name}${spring.application.name}${server.port}

位于spring-cloud-starter-netflix-eureka-client类路径上使应用程序既成为 Eureka“实例”(即,它自行注册)又成为“客户端”(它可以查询注册表以查找其他服务)。实例行为由eureka.instance.*配置键驱动,但如果您确保应用程序具有 的值spring.application.name(这是 Eureka 服务 ID 或 VIP 的默认值),则默认值就可以了。

有关可配置选项的更多详细信息,请参阅EurekaInstanceConfigBeanEurekaClientConfigBean 。

要禁用 Eureka Discovery 客户端,您可以设置eureka.client.enabledfalsespring.cloud.discovery.enabled当设置为时,Eureka Discovery 客户端也将被禁用false

目前不支持将 Spring Cloud Netflix Eureka 服务器的版本指定为路径参数。这意味着您无法在上下文路径 ( ) 中设置版本eurekaServerURLContext。相反,您可以在服务器 URL 中包含版本(例如,您可以设置)。 defaultZone: localhost:8761/eureka/v2

1.3. 使用 Eureka 服务器进行身份验证

如果其中一个eureka.client.serviceUrl.defaultZoneURL 嵌入了凭据(curl 样式,如下所示user:password@localhost:8761/eureka:),HTTP 基本身份验证会自动添加到您的 eureka 客户端。对于更复杂的需求,可以创建一个@Beanof类型并向其中DiscoveryClientOptionalArgs注入ClientFilter实例,所有这些都应用于客户端到服务器的调用。

当Eureka服务器需要客户端证书进行身份验证时,可以通过属性配置客户端证书和信任存储,如下例所示:

应用程序.yml
eureka:
  client:
    tls:
      enabled: true
      key-store: <path-of-key-store>
      key-store-type: PKCS12
      key-store-password: <key-store-password>
      key-password: <key-password>
      trust-store: <path-of-trust-store>
      trust-store-type: PKCS12
      trust-store-password: <trust-store-password>

必须eureka.client.tls.enabled为 true 才能启用 Eureka 客户端 TLS。当eureka.client.tls.trust-store省略时,将使用 JVM 默认信任存储。eureka.client.tls.key-store-type和 的默认值为eureka.client.tls.trust-store-typePKCS12。当省略密码属性时,假定密码为空。

由于 Eureka 的限制,不可能支持每个服务器的基本身份验证凭据,因此仅使用找到的第一组凭据。

如果您想自定义 Eureka HTTP 客户端使用的 RestTemplate,您可能需要创建一个 beanEurekaClientHttpRequestFactorySupplier并提供您自己的逻辑来生成ClientHttpRequestFactory实例。

Eureka HTTP 客户端使用的 RestTemplate 的所有默认超时相关属性均设置为 3 分钟(与 Apache HC5 默认值保持一致RequestConfigSocketConfig。因此,要指定超时值,必须直接使用 中的属性指定该值eureka.client.rest-template-timeout。(所有超时属性均以毫秒为单位。)

应用程序.yml
eureka:
  client:
    rest-template-timeout:
      connect-timeout: 5000
      connect-request-timeout: 8000
      socket-timeout: 10000

1.4. 状态页和健康指示器

Eureka 实例的状态页面和运行状况指示器分别默认为/info/health,它们是 Spring Boot Actuator 应用程序中有用端点的默认位置。即使对于 Actuator 应用程序,如果您使用非默认上下文路径或 servlet 路径(例如server.servletPath=/custom),您也需要更改这些内容。以下示例显示了这两个设置的默认值:

应用程序.yml
eureka:
  instance:
    statusPageUrlPath: ${server.servletPath}/info
    healthCheckUrlPath: ${server.servletPath}/health

这些链接显示在客户端使用的元数据中,并在某些情况下用于决定是否向您的应用程序发送请求,因此如果它们准确的话会很有帮助。

在 Dalston 中,更改管理上下文路径时还需要设置状态和运行状况检查 URL。从埃奇韦尔开始,这一要求已被删除。

1.5. 注册安全应用程序

如果您的应用程序想要通过 HTTPS 进行联系,您可以在 中设置两个标志EurekaInstanceConfigBean

  • eureka.instance.[nonSecurePortEnabled]=[false]

  • eureka.instance.[securePortEnabled]=[true]

这样做会使 Eureka 发布显示出对安全通信的明确偏好的实例信息。Spring Cloud始终返回以这种方式配置的服务DiscoveryClient开头的 URI 。https同样,当服务以这种方式配置时,Eureka(原生)实例信息具有安全的健康检查 URL。

由于 Eureka 内部的工作方式,它仍然会发布状态和主页的非安全 URL,除非您也显式覆盖这些 URL。您可以使用占位符来配置 eureka 实例 URL,如下例所示:

应用程序.yml
eureka:
  instance:
    statusPageUrl: https://${eureka.hostname}/info
    healthCheckUrl: https://${eureka.hostname}/health
    homePageUrl: https://${eureka.hostname}/

(请注意,这${eureka.hostname}是一个原生占位符,仅在 Eureka 的更高版本中可用。您也可以使用 Spring 占位符实现相同的效果 - 例如,通过使用${eureka.instance.hostName}。)

如果您的应用程序在代理后面运行,并且 SSL 终止在代理中(例如,如果您作为服务在 Cloud Foundry 或其他平台中运行),那么您需要确保代理“转发”标头被拦截和处理通过应用程序。如果嵌入在 Spring Boot 应用程序中的 Tomcat 容器具有“X-Forwarded-\*”标头的显式配置,则会自动发生这种情况。您的应用程序向其自身呈现的链接错误(错误的主机、端口或协议)表明您的配置有误。

1.6. 尤里卡的健康检查

默认情况下,Eureka 使用客户端心跳来确定客户端是否已启动。除非另有指定,否则 Discovery Client 不会根据 Spring Boot Actuator 传播应用程序的当前运行状况检查状态。因此,注册成功后,Eureka 始终会宣布应用程序处于“UP”状态。可以通过启用 Eureka 运行状况检查来更改此行为,从而将应用程序状态传播到 Eureka。因此,所有其他应用程序不会向处于“UP”以外状态的应用程序发送流量。以下示例展示了如何为客户端启用健康检查:

应用程序.yml
eureka:
  client:
    healthcheck:
      enabled: true
eureka.client.healthcheck.enabled=true应该只设置在application.yml. 设置该值会bootstrap.yml导致不良副作用,例如在 Eureka 中注册UNKNOWN状态。

如果您需要对运行状况检查进行更多控制,请考虑实施您自己的com.netflix.appinfo.HealthCheckHandler.

1.7. 实例和客户端的 Eureka 元数据

花一些时间了解 Eureka 元数据的工作原理是值得的,这样您就可以在您的平台中以有意义的方式使用它。主机名、IP 地址、端口号、状态页面和运行状况检查等信息有标准元数据。这些信息发布在服务注册表中,供客户端用来以简单的方式联系服务。可以将其他元数据添加到 中的实例注册中eureka.instance.metadataMap,并且可以在远程客户端中访问此元数据。通常,附加元数据不会改变客户端的行为,除非客户端了解元数据的含义。有一些特殊情况,如本文档后面所述,Spring Cloud 已经为元数据映射分配了含义。

1.7.1. 在 Cloud Foundry 上使用 Eureka

Cloud Foundry 有一个全局路由器,因此同一应用程序的所有实例都具有相同的主机名(具有类似架构的其他 PaaS 解决方案具有相同的安排)。这不一定是使用 Eureka 的障碍。但是,如果您使用路由器(推荐甚至强制,具体取决于平台的设置方式),则需要显式设置主机名和端口号(安全或非安全),以便它们使用路由器。您可能还想使用实例元数据,以便可以区分客户端上的实例(例如,在自定义负载均衡器中)。默认情况下,eureka.instance.instanceIdvcap.application.instance_id,如下例所示:

应用程序.yml
eureka:
  instance:
    hostname: ${vcap.application.uris[0]}
    nonSecurePort: 80

根据 Cloud Foundry 实例中设置安全规则的方式,您也许能够注册并使用主机 VM 的 IP 地址进行直接服务到服务调用。此功能在 Pivotal Web Services ( PWS )上尚不可用。

1.7.2. 在 AWS 上使用 Eureka

如果计划将应用程序部署到 AWS 云,则 Eureka 实例必须配置为 AWS 感知。您可以通过自定义EurekaInstanceConfigBean来实现此目的,如下所示:

@Bean
@Profile("!default")
public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) {
  EurekaInstanceConfigBean bean = new EurekaInstanceConfigBean(inetUtils);
  AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
  bean.setDataCenterInfo(info);
  return bean;
}

1.7.3。修改Eureka实例ID

普通 Netflix Eureka 实例使用与其主机名相同的 ID 进行注册(即每个主机只有一项服务)。Spring Cloud Eureka提供了一个合理的默认值,定义如下:

${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}

一个例子是myhost:myappname:8080

通过使用 Spring Cloud,您可以通过在 中提供唯一标识符来覆盖此值eureka.instance.instanceId,如以下示例所示:

应用程序.yml
eureka:
  instance:
    instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}

使用前面示例中显示的元数据以及在本地主机上部署的多个服务实例,将随机值插入其中以使实例唯一。在 Cloud Foundry 中, 是vcap.application.instance_id在 Spring Boot 应用程序中自动填充的,因此不需要随机值。

1.8. 使用 Eureka 客户端

一旦您拥有作为发现客户端的应用程序,您就可以使用它从Eureka Server发现服务实例。一种方法是使用本机com.netflix.discovery.EurekaClient(而不是 Spring Cloud DiscoveryClient),如以下示例所示:

@Autowired
private EurekaClient discoveryClient;

public String serviceUrl() {
    InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false);
    return instance.getHomePageUrl();
}

不要在方法EurekaClient@PostConstruct或方法中(或可能尚未启动的@Scheduled任何地方)使用。ApplicationContext它是在SmartLifecycle(with phase=0) 中初始化的,因此您最早可以依赖它的可用性是在另一个SmartLifecycle具有更高阶段的阶段中。

1.8.1. EurekaClient 与 Jersey

默认情况下,EurekaClient 使用 SpringRestTemplate进行 HTTP 通信。如果您希望使用 Jersey,则需要将 Jersey 依赖项添加到类路径中。以下示例显示了您需要添加的依赖项:

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
</dependency>
<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-apache-client4</artifactId>
</dependency>

1.9. 原生 Netflix EurekaClient 的替代品

您无需使用原始 Netflix EurekaClient。此外,在某种包装后面使用它通常更方便。Spring Cloud通过逻辑 Eureka 服务标识符 (VIP) 而不是物理 URL支持Feign(REST 客户端构建器)和Spring 。RestTemplate

您还可以使用org.springframework.cloud.client.discovery.DiscoveryClient,它为发现客户端提供了一个简单的 API(并非特定于 Netflix),如以下示例所示:

@Autowired
private DiscoveryClient discoveryClient;

public String serviceUrl() {
    List<ServiceInstance> list = discoveryClient.getInstances("STORES");
    if (list != null && list.size() > 0 ) {
        return list.get(0).getUri();
    }
    return null;
}

1.10. 为什么注册服务这么慢?

作为实例还涉及到注册表的定期检测信号(通过客户端serviceUrl),默认持续时间为 30 秒。除非实例、服务器和客户端在其本地缓存中都具有相同的元数据(因此可能需要 3 个心跳),否则客户端无法发现服务。您可以通过设置更改周期eureka.instance.leaseRenewalIntervalInSeconds。将其设置为小于 30 的值可以加快客户端连接到其他服务的过程。在生产中,最好坚持使用默认值,因为服务器中的内部计算会对租约续订期做出假设。

1.11. 区域

如果您已将 Eureka 客户端部署到多个区域,您可能希望这些客户端在尝试另一个区域中的服务之前使用同一区域中的服务。要进行设置,您需要正确配置 Eureka 客户端。

首先,您需要确保将 Eureka 服务器部署到每个区域,并且它们彼此是对等的。 有关详细信息,请参阅有关区域和区域的部分。

接下来,您需要告诉 Eureka 您的服务位于哪个区域。您可以通过使用该metadataMap属性来完成此操作。例如,如果service 1同时部署到zone 1zone 2,则需要在 中设置以下 Eureka 属性service 1

1 区服务 1

eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true

2区服务1

eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true

1.12. 刷新 Eureka 客户端

默认情况下,EurekaClientbean 是可刷新的,这意味着 Eureka 客户端属性可以更改和刷新。当刷新发生时,客户端将从 Eureka 服务器取消注册,并且可能会在短时间内给定服务的所有实例都不可用。消除这种情况的一种方法是禁用刷新 Eureka 客户端的功能。要做这一套eureka.client.refresh.enable=false

1.13。将 Eureka 与 Spring Cloud LoadBalancer 结合使用

我们提供对 Spring Cloud LoadBalancer 的支持ZonePreferenceServiceInstanceListSupplierzoneEureka 实例元数据 ( ) 中的值用于eureka.instance.metadataMap.zone设置用于spring-cloud-loadbalancer-zone按区域过滤服务实例的属性值。

如果缺少该标志并且该spring.cloud.loadbalancer.eureka.approximateZoneFromHostname标志设置为true,则它可以使用服务器主机名中的域名作为区域的代理。

如果没有其他区域数据源,则会根据客户端配置(而不是实例配置)进行猜测。我们采用eureka.client.availabilityZones,它是从区域名称到区域列表的映射,并提取实例自己区域的第一个区域(即 ,默认eureka.client.region为“us-east-1”,以与本机 Netflix 兼容) 。

1.14. AOT 和本机映像支持

Spring Cloud Netflix Eureka Client 集成支持 Spring AOT 转换和本机映像,但仅在禁用刷新模式的情况下。

如果您想在 AOT 或本机映像模式下运行 Eureka Client,请确保设置spring.cloud.refresh.enabledfalse

2.服务发现:Eureka Server

本节介绍如何设置 Eureka 服务器。

2.1. 如何包含 Eureka 服务器

要将 Eureka Server 包含在您的项目中,请使用组 ID 为org.springframework.cloud、工件 ID 为 的启动器spring-cloud-starter-netflix-eureka-server。有关使用当前 Spring Cloud 发布系列设置构建系统的详细信息,请参阅Spring Cloud 项目页面。

如果您的项目已经使用Thymeleaf作为模板引擎,则Eureka服务器的Freemarker模板可能无法正确加载。在这种情况下,需要手动配置模板加载器:
应用程序.yml
spring:
  freemarker:
    template-loader-path: classpath:/templates/
    prefer-file-system-access: false

2.2. 如何运行 Eureka 服务器

以下示例显示了一个最小的 Eureka 服务器:

@SpringBootApplication
@EnableEurekaServer
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

服务器有一个主页,其中包含用于正常 Eureka 功能的 UI 和 HTTP API 端点/eureka/*

以下链接有一些尤里卡背景阅读: 磁通量电容器谷歌小组讨论

由于 Gradle 的依赖解析规则以及缺少父 bom 功能,依赖spring-cloud-starter-netflix-eureka-server可能会导致应用程序启动失败。要解决此问题,请添加 Spring Boot Gradle 插件并导入 Spring cloud starter 父 bom,如下所示:

构建.gradle
buildscript {
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-docs-version}")
  }
}

apply plugin: "spring-boot"

dependencyManagement {
  imports {
    mavenBom "org.springframework.cloud:spring-cloud-dependencies:{spring-cloud-version}"
  }
}

2.3. defaultOpenForTrafficCount及其对 EurekaServer 预热时间的影响

waitTimeInMsWhenSyncEmptySpring Cloud Eureka 服务器一开始并没有考虑Netflix Eureka 的设置。为了启用预热时间,请设置eureka.server.defaultOpenForTrafficCount=0

2.4. 高可用性、区域和区域

Eureka 服务器没有后端存储,但注册表中的服务实例都必须发送心跳以保持其注册最新(因此这可以在内存中完成)。客户端还有一个 Eureka 注册的内存缓存(因此它们不必为每个服务请求都访问注册表)。

默认情况下,每个 Eureka 服务器也是一个 Eureka 客户端,并且需要(至少一个)服务 URL 来定位对等点。如果您不提供它,该服务会运行并工作,但它会在您的日志中填充大量有关无法向对等点注册的噪音。

2.5. 独立模式

两个缓存(客户端和服务器)和心跳的组合使独立的 Eureka 服务器对故障具有相当的弹性,只要有某种监视器或弹性运行时(例如 Cloud Foundry)保持其活动状态。在独立模式下,您可能更愿意关闭客户端行为,这样它就不会继续尝试连接到其对等方,但仍失败。以下示例显示如何关闭客户端行为:

application.yml(独立尤里卡服务器)
server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

请注意,serviceUrl指向与本地实例相同的主机。

2.6。同行意识

通过运行多个实例并要求它们相互注册,可以使 Eureka 更具弹性和可用性。事实上,这是默认行为,因此要使其工作,您所需要做的就是serviceUrl向对等方添加 valid 值,如以下示例所示:

application.yml(两个对等感知尤里卡服务器)
---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1
  client:
    serviceUrl:
      defaultZone: https://peer2/eureka/

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: https://peer1/eureka/

peer1在前面的示例中,我们有一个 YAML 文件,可通过在不同的 Spring 配置文件中运行它来在两个主机 (和)上运行同一服务器peer2/etc/hosts您可以使用此配置通过操作解析主机名来测试单个主机上的对等感知(在生产中这样做没有太大价值) 。事实上,eureka.instance.hostname如果您运行的计算机知道自己的主机名(默认情况下,使用 进行查找java.net.InetAddress),则不需要 。

您可以将多个对等点添加到系统中,并且只要它们都通过至少一条边缘相互连接,它们就会在它们之间同步注册。如果对等点在物理上是分开的(在数据中心内部或多个数据中心之间),那么原则上系统可以承受“裂脑”类型的故障。您可以将多个对等点添加到系统中,只要它们都直接相互连接,它们就会在它们之间同步注册。

application.yml(三个对等感知 Eureka 服务器)
eureka:
  client:
    serviceUrl:
      defaultZone: https://peer1/eureka/,http://peer2/eureka/,http://peer3/eureka/

---
spring:
  profiles: peer1
eureka:
  instance:
    hostname: peer1

---
spring:
  profiles: peer2
eureka:
  instance:
    hostname: peer2

---
spring:
  profiles: peer3
eureka:
  instance:
    hostname: peer3

2.7. 何时首选 IP 地址

在某些情况下,Eureka 最好公布服务的 IP 地址而不是主机名。设置eureka.instance.preferIpAddresstrue,当应用程序向 eureka 注册时,它使用其 IP 地址而不是主机名。

如果 Java 无法确定主机名,则将 IP 地址发送到 Eureka。设置主机名的唯一显式方法是设置eureka.instance.hostname属性。您可以使用环境变量在运行时设置主机名 - 例如eureka.instance.hostname=${HOST_NAME}.

2.8. 保护 Eureka 服务器的安全

您只需通过将 Spring Security 添加到服务器的类路径即可保护您的 Eureka 服务器spring-boot-starter-security。默认情况下,当 Spring Security 位于类路径上时,它将要求向应用程序的每个请求发送有效的 CSRF 令牌。Eureka 客户端通常不会拥有有效的跨站点请求伪造 (CSRF) 令牌,您需要禁用端点的此要求/eureka/**。例如:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests((authz) -> authz
        .anyRequest().authenticated())
        .httpBasic(withDefaults());
    http.csrf().ignoringRequestMatchers("/eureka/**");
    return http.build();
}

有关 CSRF 的更多信息,请参阅Spring Security 文档

可以在 Spring Cloud Samples存储库中找到演示 Eureka Server 。

2.9. JDK 11 支持

Eureka 服务器所依赖的 JAXB 模块已在 JDK 11 中删除。如果您打算在运行 Eureka 服务器时使用 JDK 11,则必须在 POM 或 Gradle 文件中包含这些依赖项。

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
</dependency>

2.10. AOT 和本机映像支持

Spring Cloud Netflix Eureka Server 不支持 Spring AOT 转换或本机映像。

3. 配置属性

要查看所有 Spring Cloud Netflix 相关配置属性的列表,请查看附录页面