1. 服务发现:Eureka 客户端

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

1.1. 如何包含 Eureka 客户端

要将 Eureka 客户端包含在项目中,请使用组 ID 为且工件 ID 为 的Starters。 有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅 Spring Cloud 项目页面org.springframework.cloudspring-cloud-starter-netflix-eureka-clientspring-doc.cn

1.2. 注册 Eureka

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

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

@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 应用程序。 通过在 Classpath 上,您的应用程序会自动向 Eureka 服务器注册。需要配置才能找到 Eureka 服务器,如以下示例所示:spring-cloud-starter-netflix-eureka-clientspring-doc.cn

application.yml
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

在前面的示例中,是一个魔术字符串回退值,该值为任何不表示首选项的客户端提供服务 URL(换句话说,它是一个有用的默认值)。defaultZonespring-doc.cn

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

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

在 Classpath 上使应用程序同时成为 Eureka“实例”(即,它注册自己)和“客户端”(它可以查询注册表以查找其他服务)。 实例行为由配置键驱动,但是如果您确保应用程序具有 的值(这是 Eureka 服务 ID 或 VIP 的默认值),则默认值很好。spring-cloud-starter-netflix-eureka-clienteureka.instance.*spring.application.namespring-doc.cn

有关可配置选项的更多详细信息,请参见EurekaInstanceConfigBeanEurekaClientConfigBeanspring-doc.cn

要禁用 Eureka Discovery Client,可以设置为 。当 设置为 时,Eureka Discovery Client 也将被禁用。eureka.client.enabledfalsespring.cloud.discovery.enabledfalsespring-doc.cn

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

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

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

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

application.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 客户端 TLS,需要为 true。如果省略,则使用 JVM 默认信任存储。和 的默认值为 PKCS12。如果省略 password 属性,则假定 password 为空。eureka.client.tls.enabledeureka.client.tls.trust-storeeureka.client.tls.key-store-typeeureka.client.tls.trust-store-typespring-doc.cn

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

如果要自定义 Eureka HTTP Client 使用的RestTemplate,则可能需要创建一个 bean 并提供自己的逻辑来生成实例。EurekaClientHttpRequestFactorySupplierClientHttpRequestFactoryspring-doc.cn

Eureka HTTP Client 使用的 RestTemplate 的所有默认超时相关属性都设置为无限。因此,要指定超时值,必须直接使用 中的属性指定值。(所有 timeout 属性均以毫秒为单位。eureka.client.rest-template-timeoutspring-doc.cn

application.yml
eureka:
  client:
    rest-template-timeout:
      connect-timeout: 5000
      connect-request-timeout: 8000
      socket-timeout: 10000

1.4. 状态页面和健康指示器

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

application.yml
eureka:
  instance:
    statusPageUrlPath: ${server.servletPath}/info
    healthCheckUrlPath: ${server.servletPath}/health

这些链接显示在客户端使用的元数据中,并在某些情况下用于决定是否向应用程序发送请求,因此如果它们准确,将非常有用。spring-doc.cn

在 Dalston 中,还需要在更改时设置状态和运行状况检查 URL 那个 管理 上下文 路径。从 Edgware 开始,此要求已删除。

1.5. 注册安全应用程序

如果希望通过 HTTPS 联系您的应用,您可以在 :EurekaInstanceConfigBeanspring-doc.cn

这样做会使 Eureka 发布实例信息,该信息显示对安全通信的明确偏好。 Spring Cloud 始终返回以这种方式配置的服务的 URI 开头。 同样,当以这种方式配置服务时,Eureka(本机)实例信息具有安全的运行状况检查 URL。DiscoveryClienthttpsspring-doc.cn

由于 Eureka 在内部的工作方式,它仍然会为状态和主页发布不安全的 URL,除非您还显式覆盖了它们。 您可以使用占位符来配置 eureka 实例 URL,如以下示例所示:spring-doc.cn

application.yml
eureka:
  instance:
    statusPageUrl: https://${eureka.hostname}/info
    healthCheckUrl: https://${eureka.hostname}/health
    homePageUrl: https://${eureka.hostname}/

(请注意,这是仅可用的本机占位符 在 Eureka 的更高版本中。你可以用 Spring 占位符 — 例如,通过使用 。${eureka.hostname}${eureka.instance.hostName}spring-doc.cn

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

1.6. Eureka 的健康检查

默认情况下,Eureka 使用 client 检测信号来确定 client 是否已启动。 除非另有说明,否则 Discovery Client 不会根据 Spring Boot Actuator 传播应用程序的当前运行状况检查状态。 因此,在成功注册后,Eureka 始终宣布应用程序处于“UP”状态。可以通过启用 Eureka 运行状况检查来更改此行为,这会导致将应用程序状态传播到 Eureka。 因此,所有其他应用程序都不会将流量发送到处于“UP”以外的状态的应用程序。 以下示例显示如何为客户端启用运行状况检查:spring-doc.cn

application.yml
eureka:
  client:
    healthcheck:
      enabled: true
eureka.client.healthcheck.enabled=true应仅在 中设置。在中设置值会导致不良的副作用,例如在 Eureka 中注册 status 。application.ymlbootstrap.ymlUNKNOWN

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

1.7. 实例和 Client 端的 Eureka 元数据

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

1.7.1. 在 Cloud Foundry 上使用 Eureka

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

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

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

1.7.2. 在 AWS 上使用 Eureka

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

@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-doc.cn

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

例如。myhost:myappname:8080spring-doc.cn

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

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

使用前面示例中显示的元数据和在 localhost 上部署的多个服务实例,将随机值插入其中以使实例唯一。 在 Cloud Foundry 中,它会在 Spring Boot 应用程序中自动填充,因此不需要 random 值。vcap.application.instance_idspring-doc.cn

1.8. 使用 EurekaClient

一旦你有一个作为发现客户端的应用程序,就可以使用它从 Eureka 服务器发现服务实例。 一种方法是使用 native (而不是 Spring Cloud ),如以下示例所示:com.netflix.discovery.EurekaClientDiscoveryClientspring-doc.cn

@Autowired
private EurekaClient discoveryClient;

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

不要在 method 或 in a method(或任何可能尚未启动 的地方)使用 。 它是在 (with ) 中初始化的,因此您最早可以依赖它可用的是在另一个具有更高相位的 phase 中。EurekaClient@PostConstruct@ScheduledApplicationContextSmartLifecyclephase=0SmartLifecyclespring-doc.cn

1.8.1. 带有 Jersey 的 EurekaClient

默认情况下,EurekaClient使用 Spring 的进行 HTTP 通信。 如果您希望改用 Jersey,则需要将 Jersey 依赖项添加到您的 Classpath 中。 以下示例显示了您需要添加的依赖项:RestTemplatespring-doc.cn

<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 . 此外,在某种包装器后面使用它通常更方便。 Spring Cloud 通过逻辑 Eureka 服务标识符 (VIP) 而不是物理 URL 支持 Feign(一种 REST 客户端构建器)和 Spring Cloud LoadBalancerEurekaClientspring-doc.cn

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

@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. 为什么注册服务这么慢?

作为实例还涉及对注册表的定期检测信号 (通过客户端的 ),默认持续时间为 30 秒。 只有在实例、服务器和客户端的本地元数据中都具有相同的元数据后,客户端才能发现服务 cache (所以可能需要 3 次心跳)。 您可以通过设置 来更改期间。 将其设置为小于 30 的值可加快客户端连接到其他服务的过程。 在 生产环境中,最好坚持使用默认值,因为服务器中的内部计算会对租约续订期做出假设。serviceUrleureka.instance.leaseRenewalIntervalInSecondsspring-doc.cn

1.11. 区域

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

首先,您需要确保已将 Eureka 服务器部署到每个区域,并且 他们是彼此的同伴。 有关更多信息,请参阅有关区域和区域的部分。spring-doc.cn

接下来,您需要告诉 Eureka 您的服务位于哪个区域。 您可以使用 该属性 . 例如,如果同时部署到 和 ,则需要在 中设置以下 Eureka 属性:metadataMapservice 1zone 1zone 2service 1spring-doc.cn

区域 1 中的服务 1spring-doc.cn

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

区域 2 中的服务 1spring-doc.cn

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

1.12. 刷新 Eureka 客户端

默认情况下,bean 是可刷新的,这意味着可以更改和刷新 Eureka Client 端属性。 当刷新发生时,客户端将从 Eureka 服务器中注销,并且可能会有短暂的片刻 其中给定服务的所有实例都不可用。消除这种情况发生的一种方法是禁用 刷新 Eureka 客户端的能力。要执行此操作,请将 .EurekaClienteureka.client.refresh.enable=falsespring-doc.cn

1.13. 将 Eureka 与 Spring Cloud LoadBalancer 一起使用

我们提供对 Spring Cloud LoadBalancer 的支持。 Eureka 实例元数据 () 中的值用于设置 用于按区域筛选服务实例的属性的值。ZonePreferenceServiceInstanceListSupplierzoneeureka.instance.metadataMap.zonespring-cloud-loadbalancer-zonespring-doc.cn

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

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