文章摘要(AI生成)
该项目通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习语为 Spring Boot 应用程序提供 Netflix OSS 集成。通过一些简单的注释,您可以快速启用和配置应用程序中的常见模式,并使用经过实战考验的 Netflix 组件构建大型分布式系统。提供的模式包括服务发现
Spring Cloud Netflix
该项目通过自动配置和绑定到 Spring 环境和其他 Spring 编程模型习语,为 Spring Boot 应用程序提供 Netflix OSS 集成。通过一些简单的注释,您可以快速启用和配置应用程序中的常见模式,并使用久经考验的 Netflix 组件构建大型分布式系统。提供的模式包括服务发现 (Eureka)。
1. 服务发现:Eureka Clients
服务发现是基于微服务的架构的关键原则之一。尝试手动配置每个客户端或某种形式的约定可能很难做到,而且可能很脆弱。Eureka 是 Netflix 服务发现服务器和客户端。服务器可以配置和部署为高可用性,每个服务器都将注册服务的状态复制给其他服务器。
1.1. 如何包含 Eureka 客户端
要在您的项目中包含 Eureka 客户端,请使用组 IDorg.springframework.cloud
和工件 ID 的启动器spring-cloud-starter-netflix-eureka-client
。有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅Spring Cloud 项目页面。
1.2. 注册eureka
当客户端向 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服务器,如下例所示:
application.yml
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
在前面的示例中,defaultZone
是一个神奇的字符串回退值,它为任何未表达偏好的客户端提供服务 URL(换句话说,它是一个有用的默认值)。
该
defaultZone
属性区分大小写并且需要驼峰式大小写,因为该serviceUrl
属性是一个Map<String, String>
. 因此,该defaultZone
属性不遵循正常的 Spring Boot snake-case 约定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 的默认值),则默认值就可以了。
有关可配置选项的更多详细信息,请参阅EurekaInstanceConfigBean和EurekaClientConfigBean。
要禁用 Eureka Discovery Client,您可以设置eureka.client.enabled
为false
. spring.cloud.discovery.enabled
当设置为时,Eureka Discovery Client 也将被禁用false
。
目前不支持将 Spring Cloud Netflix Eureka 服务器的版本指定为路径参数。这意味着您不能在上下文路径 (
eurekaServerURLContext
) 中设置版本。相反,您可以在服务器 URL 中包含版本(例如,您可以设置)。defaultZone: localhost:8761/eureka/v2
1.3. 使用 Eureka 服务器进行身份验证
eureka.client.serviceUrl.defaultZone
如果其中一个URL 中嵌入了凭据(curl 样式,如下所示:),HTTP 基本身份验证会自动添加到您的 eureka 客户端user:password@localhost:8761/eureka
。对于更复杂的需求,你可以创建一个@Bean
of类型DiscoveryClientOptionalArgs
并向其中注入ClientFilter
实例,所有这些都应用于客户端对服务器的调用。
当 Eureka 服务器需要客户端证书进行身份验证时,可以通过属性配置客户端证书和信任库,如下例所示:
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.client.tls.enabled
需要 true 才能启用 Eureka 客户端 TLS 。eureka.client.tls.trust-store
省略时,将使用 JVM 默认信任库。eureka.client.tls.key-store-type
和的默认值为eureka.client.tls.trust-store-type
PKCS12。省略密码属性时,假定为空密码。
由于 Eureka 的限制,不可能支持每台服务器的基本身份验证凭据,因此仅使用找到的第一组。
如果您想自定义 Eureka HTTP 客户端使用的 RestTemplate,您可能需要创建一个 beanEurekaClientHttpRequestFactorySupplier
并提供您自己的逻辑来生成ClientHttpRequestFactory
实例。
Eureka HTTP 客户端使用的 RestTemplate 的所有默认超时相关属性都设置为 3 分钟(与 Apache HC5 默认值保持一致RequestConfig
)SocketConfig
。因此,要指定超时值,您必须直接使用 中的属性指定值eureka.client.rest-template-timeout
。(所有超时属性都以毫秒为单位。)
application.yml
eureka:
client:
rest-template-timeout:
connect-timeout: 5000
connect-request-timeout: 8000
socket-timeout: 10000
1.4. 状态页面和健康指标
Eureka 实例的状态页面和健康指标分别默认为/info
和/health
,它们是 Spring Boot Actuator 应用程序中有用端点的默认位置。如果您使用非默认上下文路径或 servlet 路径(例如server.servletPath=/custom
),您需要更改这些,即使对于 Actuator 应用程序也是如此。以下示例显示了这两个设置的默认值:
application.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 CloudDiscoveryClient
总是返回一个以 开头的 URI 。https
同样,当一个服务这样配置时,Eureka(原生)实例信息就有一个安全的健康检查URL。
由于 Eureka 的内部工作方式,它仍然会为状态和主页发布一个非安全的 URL,除非您也明确地覆盖它们。您可以使用占位符来配置 eureka 实例 URL,如以下示例所示:
application.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 的健康检查
默认情况下,Eureka 使用客户端心跳来确定客户端是否已启动。除非另有说明,否则 Discovery Client 不会根据 Spring Boot Actuator 传播应用程序的当前健康检查状态。因此,在成功注册后,Eureka 总是宣布应用程序处于“UP”状态。可以通过启用 Eureka 健康检查来更改此行为,这会导致将应用程序状态传播到 Eureka。因此,其他所有应用程序都不会向处于“UP”以外状态的应用程序发送流量。以下示例显示了如何为客户端启用健康检查:
application.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.instanceId
是vcap.application.instance_id
,如以下示例所示:
application.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
,如以下示例所示:
application.yml
eureka:
instance:
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
使用前面示例中显示的元数据和部署在 localhost 上的多个服务实例,随机值被插入到那里以使实例唯一。在 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
(withphase=0
) 中初始化,因此您最早可以依赖它的可用性是在另一个SmartLifecycle
更高阶段。
1.8.1. 带有 Jersey 的 EurekaClient
默认情况下,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 1
和zone 2
,则需要在 中设置以下 Eureka 属性service 1
:
zone 1 服务 1
eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true
zone 2 服务 1
eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true
1.12. 刷新 Eureka 客户端
默认情况下,EurekaClient
bean 是可刷新的,这意味着可以更改和刷新 Eureka 客户端属性。当发生刷新时,客户端将从 Eureka 服务器注销,并且可能会在短时间内给定服务的所有实例都不可用。消除这种情况发生的一种方法是禁用刷新 Eureka 客户端的能力。做这一套eureka.client.refresh.enable=false
。
1.13. 将 Eureka 与 Spring Cloud LoadBalancer 结合使用
我们提供对 Spring Cloud LoadBalancer 的支持ZonePreferenceServiceInstanceListSupplier
。zone
来自 Eureka 实例元数据 ( )的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 客户端,请确保设置
spring.cloud.refresh.enabled
为false
2. 服务发现:Eureka Server
本节介绍如何设置 Eureka 服务器。
2.1. 如何包含 Eureka 服务器
要在您的项目中包含 Eureka Server,请使用组 IDorg.springframework.cloud
和工件 ID 的启动器spring-cloud-starter-netflix-eureka-server
。有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅Spring Cloud 项目页面。
如果您的项目已经使用 Thymeleaf 作为其模板引擎,则可能无法正确加载 Eureka 服务器的 Freemarker 模板。在这种情况下,需要手动配置模板加载器:
application.yml
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
2.2. 如何运行Eureka服务器
以下示例显示了一个最小的 Eureka 服务器:
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
服务器有一个带有 UI 和 HTTP API 端点的主页,用于正常的 Eureka 功能/eureka/*
。
以下链接包含一些 Eureka 背景阅读材料:flux capacitor和google group discussion。
由于Gradle的依赖解析规则和父bom特性的缺失,依赖
spring-cloud-starter-netflix-eureka-server
会导致应用启动失败。要解决此问题,请添加 Spring Boot Gradle 插件并导入 Spring cloud starter parent bom,如下所示: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
及其对 EurekaServer 预热时间的影响
Netflix Eureka 的waitTimeInMsWhenSyncEmpty
设置一开始在 Spring Cloud Eureka 服务器中没有考虑。为了启用预热时间,设置eureka.server.defaultOpenForTrafficCount=0
.
2.4. 高可用性、区域和地区
Eureka 服务器没有后端存储,但是注册表中的服务实例都必须发送心跳以保持它们的注册是最新的(因此这可以在内存中完成)。客户端也有一个 Eureka 注册的内存缓存(因此他们不必为每个服务请求都去注册表)。
默认情况下,每个 Eureka 服务器也是一个 Eureka 客户端,并且需要(至少一个)服务 URL 来定位对等点。如果您不提供它,该服务会运行并工作,但它会在您的日志中填满大量关于无法向对等点注册的噪音。
2.5. 独立模式
两个缓存(客户端和服务器)和心跳的组合使独立的 Eureka 服务器对故障具有相当的弹性,只要有某种监视器或弹性运行时(例如 Cloud Foundry)保持它的活动。在独立模式下,您可能更愿意关闭客户端行为,这样它就不会一直尝试并无法访问其对等方。以下示例显示了如何关闭客户端行为:
application.yml(独立 Eureka 服务器)
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(两个 Peer Aware Eureka 服务器)
---
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 服务器)
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.preferIpAddress
为true
并且,当应用程序向 eureka 注册时,它使用其 IP 地址而不是其主机名。
如果 Java 无法确定主机名,则将 IP 地址发送到 Eureka。设置主机名的唯一明确方法是设置
eureka.instance.hostname
属性。您可以使用环境变量在运行时设置您的主机名——例如,eureka.instance.hostname=${HOST_NAME}
.
2.8. 保护尤里卡服务器
您只需通过将 Spring Security 添加到服务器的类路径即可保护您的 Eureka 服务器spring-boot-starter-security
。默认情况下,当 Spring Security 在类路径上时,它将要求将有效的 CSRF 令牌与对应用程序的每个请求一起发送。Eureka 客户端通常不会拥有有效的跨站点请求伪造 (CSRF) 令牌,您需要为/eureka/**
端点禁用此要求。例如:
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http);
}
}
有关 CSRF 的更多信息,请参阅Spring Security 文档。
可以在 Spring Cloud Samples repo中找到演示 Eureka Server 。
2.9. JDK 11 支持
JDK 11 中删除了 Eureka 服务器所依赖的 JAXB 模块。如果您打算在运行 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 相关配置属性的列表,请查看附录页面。
评论区