Spring Cloud Netflix(网飞)

时间:2022-12-02 12:17:18

Spring Cloud Netflix(网飞)

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

1. 服务发现:尤里卡客户端

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

1.1. 如何包含尤里卡客户端

要在项目中包含 Eureka 客户端,请使用组 ID 为 和工件 ID 为 的初学者。 有关使用当前 Spring 云发布系列设置构建系统的详细信息,请参阅Spring 云项目页面。org.springframework.cloudspring-cloud-starter-netflix-eureka-client

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 引导应用程序。 通过拥有类路径,您的应用程序会自动向 Eureka 服务器注册。需要配置才能找到 Eureka 服务器,如以下示例所示:​​spring-cloud-starter-netflix-eureka-client​

应用程序.yml

eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/

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

该属性区分大小写,并且需要驼峰大小写,因为该属性是 a。因此,该属性不遵循正常的弹簧靴蛇案例惯例。​​defaultZone​​​​serviceUrl​​​​Map<String, String>​​​​defaultZone​​​​default-zone​

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

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

请参阅 EurekaInstanceConfigBean 和EurekaClientConfigBean了解有关可配置选项的更多详细信息。

要禁用尤里卡发现客户端,您可以设置为。尤里卡发现客户端也将在设置为 时被禁用。​​eureka.client.enabled​​​​false​​​​spring.cloud.discovery.enabled​​​​false​

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

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

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

需要为真才能启用尤里卡客户端 TLS。省略时,将使用 JVM 缺省信任存储区。默认值为 PKCS12。省略密码属性时,将假定密码为空。​​eureka.client.tls.enabled​​​​eureka.client.tls.trust-store​​​​eureka.client.tls.key-store-type​​​​eureka.client.tls.trust-store-type​

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

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

1.4. 状态页面和运行状况指示器

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

应用程序.yml

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

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

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

1.5. 注册安全应用程序

如果希望通过 HTTPS 联系你的应用,您可以在以下位置设置两个标志:​​EurekaInstanceConfigBean​

  • ​eureka.instance.[nonSecurePortEnabled]=[false]​
  • ​eureka.instance.[securePortEnabled]=[true]​

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

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

应用程序.yml

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

(请注意,本机占位符仅可用 在尤里卡的更高版本中。你可以用同样的事情实现 春季占位符也是如此 - 例如,通过使用。​​${eureka.hostname}​​​​${eureka.instance.hostName}​

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

1.6. 尤里卡的健康检查

默认情况下,Eureka 使用客户端检测信号来确定客户端是否已启动。 除非另有指定,否则发现客户端不会根据 Spring 引导执行器传播应用程序的当前运行状况检查状态。 因此,成功注册后,尤里卡总是宣布应用程序处于“UP”状态。可以通过启用 Eureka 运行状况检查来更改此行为,这将导致将应用程序状态传播到 Eureka。 因此,所有其他应用程序都不会将流量发送到状态为“UP”以外的应用程序。 以下示例演示如何为客户端启用运行状况检查:

应用程序.yml

eureka:
client:
healthcheck:
enabled: true

​eureka.client.healthcheck.enabled=true​​​应该只设置在。设置该值会导致不良的副作用,例如在尤里卡注册 anstatus。​​application.yml​​​​bootstrap.yml​​​​UNKNOWN​

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

1.7. 实例和客户端的尤里卡元数据

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

1.7.1. 在Cloud Foundry上使用尤里卡

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

应用程序.yml

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

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

1.7.2. 在 AWS 上使用尤里卡

如果计划将应用程序部署到 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. 更改尤里卡实例 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中,它们会自动填充在Spring Boot应用程序中,因此不需要随机值。​​vcap.application.instance_id​

1.8. 使用尤里卡客户端

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

@Autowired
private EurekaClient discoveryClient;

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


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


1.8.1. 尤里卡泽西客户

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

<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 尤里卡客户端的替代品

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

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

@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 秒。 在实例、服务器和客户端的本地元数据都相同之前,客户端无法发现服务。 缓存(因此可能需要 3 个心跳)。 您可以通过设置更改时间段。 将其设置为小于 30 的值可加快客户端连接到其他服务的过程。 在生产中,最好坚持使用默认值,因为服务器中的内部计算对租约续订期进行了假设。​​serviceUrl​​​​eureka.instance.leaseRenewalIntervalInSeconds​

1.11. 区域

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

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

接下来,您需要告诉尤里卡您的服务位于哪个区域。 您可以使用属性来执行此操作。 例如,如果 ifis 部署到 bothand,则需要在 中设置以下 Eureka 属性:​​metadataMap​​​​service 1​​​​zone 1​​​​zone 2​​​​service 1​

区域 1 中的服务 1

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

区域 1 中的服务 2

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

1.12. 刷新尤里卡客户端

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

1.13. 将尤里卡与 Spring 云负载均衡器结合使用

我们为Spring Cloud LoadBalancer提供支持。 来自 Eureka 实例元数据 () 的值用于设置 属性值,用于按区域筛选服务实例。​​ZonePreferenceServiceInstanceListSupplier​​​​zone​​​​eureka.instance.metadataMap.zone​​​​spring-cloud-loadbalancer-zone​

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

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

2. 服务发现:尤里卡服务器

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

2.1. 如何包含尤里卡服务器

要在项目中包含 Eureka 服务器,请使用组 ID 为 和工件 ID 为 的初学者。 有关使用当前 Spring 云发布系列设置构建系统的详细信息,请参阅Spring 云项目页面。​​org.springframework.cloud​​​​spring-cloud-starter-netflix-eureka-server​

如果您的项目已经使用 Thymeleaf 作为其模板引擎,则 Eureka 服务器的 Freemarker 模板可能无法正确加载。在这种情况下,需要手动配置模板加载器:

应用程序.yml

spring:
freemarker:
template-loader-path: classpath:/templates/
prefer-file-system-access: false

2.2. 如何运行尤里卡服务器

以下示例显示了一个最小的 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 Boot Gradle 插件并导入 Spring 云启动器父 bom,如下所示:​​spring-cloud-starter-netflix-eureka-server​



build.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及其对Eureka服务器预热时间的影响

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

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

Eureka 服务器没有后端存储,但注册表中的服务实例都必须发送检测信号以使其注册保持最新(因此可以在内存中完成此操作)。 客户端还具有 Eureka 注册的内存中缓存(因此它们不必为每次向服务发出请求而转到注册表)。

默认情况下,每个 Eureka 服务器也是 Eureka 客户端,并且需要(至少一个)服务 URL 才能找到对等方。 如果您不提供它,服务将运行并正常工作,但它会用大量关于无法向对等方注册的噪音填充您的日志。

2.5. 独立模式

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

application.yml (Standalone Eureka Server)

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 更具弹性和可用性。 实际上,这是默认行为,因此要使其正常工作,您需要做的就是将 valida 添加到对等方,如以下示例所示:​​serviceUrl​

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/

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

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

application.yml(三个对等感知尤里卡服务器)

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 地址而不是主机名。 Settoand,当应用程序向 Eureka 注册时,它使用其 IP 地址而不是主机名。​​eureka.instance.preferIpAddress​​​​true​


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


2.8. 保护尤里卡服务器

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

@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http);
}
}

有关 CSRF 的更多信息,请参阅Spring 安全性文档。

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

2.9. JDK 11 支持

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

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