Spring Cloud Netflix 功能
服务发现:Eureka 客户端
服务发现是基于微服务的架构的关键原则之一。 尝试手动配置每个客户端或某种形式的约定可能很难做到,而且可能很脆弱。 Eureka 是 Netflix 服务发现服务器和客户端。 可以将服务器配置和部署为高可用性,每个服务器都将已注册服务的状态复制到其他服务器。
如何包含 Eureka 客户端
要将 Eureka Client 包含在您的项目中,请使用组 ID 为org.springframework.cloud
工件 ID 为spring-cloud-starter-netflix-eureka-client
.
有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅 Spring Cloud 项目页面。
注册 Eureka
当客户端向 Eureka 注册时,它会提供有关自身的元数据,例如主机、端口、运行状况指示器 URL、主页和其他详细信息。 Eureka 从属于服务的每个实例接收检测信号消息。 如果检测信号在可配置的时间表上发生故障,则通常会从注册表中删除该实例。
以下示例显示了一个最小的 Eureka 客户端应用程序:
@SpringBootApplication
@RestController
public class Application {
@RequestMapping("/")
public String home() {
return "Hello world";
}
public static void main(String[] args) {
SpringApplication.run(CustomerServiceTestApplication.class, args);
}
}
请注意,前面的示例显示了一个普通的 Spring Boot 应用程序。
通过拥有spring-cloud-starter-netflix-eureka-client
在 Classpath 上,您的应用程序会自动向 Eureka 服务器注册。需要配置才能找到 Eureka 服务器,如以下示例所示:
eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/
在前面的示例中,defaultZone
是一个魔术字符串回退值,它为任何不表示首选项的客户端提供服务 URL(换句话说,它是一个有用的默认值)。
这defaultZone 属性区分大小写,并且需要驼峰式大小写,因为serviceUrl property 是一个Map<String, String> .因此,defaultZone 属性不遵循正常的 Spring Boot 蛇形大小写约定default-zone . |
默认应用程序名称(即服务 ID)、虚拟主机和非安全端口(取自Environment
) 是${spring.application.name}
,${spring.application.name}
和${server.port}
分别。
拥有spring-cloud-starter-netflix-eureka-client
在 Classpath 上,使应用程序同时成为 Eureka“实例”(即,它注册自己)和“客户端”(它可以查询注册表以查找其他服务)。
实例行为由eureka.instance.*
配置键,但如果您确保应用程序具有spring.application.name
(这是 Eureka 服务 ID 或 VIP 的默认值)。
有关可配置选项的更多详细信息,请参见EurekaInstanceConfigBean和EurekaClientConfigBean。
要禁用 Eureka Discovery Client,您可以设置eureka.client.enabled
自false
.在以下情况下,Eureka Discovery Client 也将被禁用spring.cloud.discovery.enabled
设置为false
.
目前不支持将 Spring Cloud Netflix Eureka 服务器的版本指定为 path 参数。这意味着您无法在上下文路径 (eurekaServerURLContext ).相反,您可以在服务器 URL 中包含版本(例如,您可以将defaultZone: localhost:8761/eureka/v2 ). |
使用 Eureka 服务器进行身份验证
如果eureka.client.serviceUrl.defaultZone
URL 中嵌入了凭据(curl 样式,如下所示:user:password@localhost:8761/eureka
).
对于更复杂的需求,您可以创建一个@Bean
的类型DiscoveryClientOptionalArgs
并注入ClientFilter
实例,所有这些都应用于从客户端到服务器的调用。
当 Eureka 服务器需要客户端证书进行身份验证时,可以通过属性配置客户端证书和信任存储,如以下示例所示:
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。如果省略 password 属性,则假定 password 为空。
由于 Eureka 中的限制,无法支持每个服务器的基本身份验证凭据,因此仅使用找到的第一组。 |
如果要自定义 Eureka HTTP 客户端使用的 RestTemplate,则可能需要创建一个EurekaClientHttpRequestFactorySupplier
并提供您自己的逻辑来生成ClientHttpRequestFactory
实例。
Eureka HTTP Client 使用的RestTemplate的所有默认超时相关属性都设置为 3 分钟(与 Apache HC5 默认值保持一致RequestConfig
和SocketConfig
).因此,要指定超时值,必须直接使用eureka.client.rest-template-timeout
.(所有 timeout 属性均以毫秒为单位。
eureka:
client:
rest-template-timeout:
connect-timeout: 5000
connect-request-timeout: 8000
socket-timeout: 10000
状态页面和运行状况指示器
Eureka 实例的状态页面和运行状况指示器默认为/info
和/health
分别是 Spring Boot Actuator 应用程序中有用端点的默认位置。
你需要更改这些内容,即使对于 Actuator 应用程序,如果你使用非默认上下文路径或 servlet 路径(例如server.servletPath=/custom
).以下示例显示了这两个设置的默认值:
eureka: instance: statusPageUrlPath: ${server.servletPath}/info healthCheckUrlPath: ${server.servletPath}/health
这些链接显示在客户端使用的元数据中,并在某些情况下用于决定是否向应用程序发送请求,因此如果它们准确,将非常有用。
在 Dalston 中,还需要在更改时设置状态和运行状况检查 URL 那个 管理 上下文 路径。从 Edgware 开始,此要求已删除。 |
注册安全应用程序
如果希望通过 HTTPS 联系您的应用,您可以在EurekaInstanceConfigBean
:
-
eureka.instance.[nonSecurePortEnabled]=[false]
-
eureka.instance.[securePortEnabled]=[true]
这样做会使 Eureka 发布实例信息,该信息显示对安全通信的明确偏好。
The Spring CloudDiscoveryClient
始终返回以https
对于以这种方式配置的服务。
同样,当以这种方式配置服务时,Eureka(本机)实例信息具有安全的运行状况检查 URL。
由于 Eureka 在内部的工作方式,它仍然会为状态和主页发布不安全的 URL,除非您还显式覆盖了它们。 您可以使用占位符来配置 eureka 实例 URL,如以下示例所示:
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-\*' 标头的显式配置,则会自动发生这种情况。 你的应用呈现的指向自身错误(错误的主机、端口或协议)的链接表明你把这个配置弄错了。 |
Eureka 的运行状况检查
默认情况下,Eureka 使用 client 检测信号来确定 client 是否已启动。 除非另有说明,否则 Discovery Client 不会根据 Spring Boot Actuator 传播应用程序的当前运行状况检查状态。 因此,在成功注册后,Eureka 始终宣布应用程序处于“UP”状态。可以通过启用 Eureka 运行状况检查来更改此行为,这会导致将应用程序状态传播到 Eureka。 因此,所有其他应用程序都不会将流量发送到处于“UP”以外的状态的应用程序。 以下示例显示如何为客户端启用运行状况检查:
eureka: client: healthcheck: enabled: true
eureka.client.healthcheck.enabled=true 应仅在application.yml .在bootstrap.yml 会导致不良的副作用,例如在 Eureka 中使用UNKNOWN 地位。 |
如果您需要对运行状况检查进行更多控制,请考虑实施自己的com.netflix.appinfo.HealthCheckHandler
.
实例和客户端的 Eureka 元数据
花一点时间了解 Eureka 元数据的工作原理是值得的,这样您就可以以在您的平台中有意义的方式使用它。
主机名、IP 地址、端口号、状态页面和运行状况检查等信息都有标准元数据。
这些 ID 发布在 service registry 中,并供客户端使用,以便以简单的方式联系服务。
可以将其他元数据添加到eureka.instance.metadataMap
,并且此元数据可在远程客户端中访问。
通常,其他元数据不会更改客户端的行为,除非客户端知道元数据的含义。
有几种特殊情况,如本文档后面所述,其中 Spring Cloud 已经为元数据映射分配了含义。
在 Cloud Foundry 上使用 Eureka
Cloud Foundry 具有全局路由器,因此同一应用程序的所有实例具有相同的主机名(具有类似体系结构的其他 PaaS 解决方案具有相同的安排)。
这不一定是使用 Eureka 的障碍。
但是,如果您使用路由器(推荐或强制,具体取决于您的平台设置方式),则需要显式设置主机名和端口号(安全或非安全),以便它们使用路由器。
您可能还希望使用实例元数据,以便可以区分客户端上的实例(例如,在自定义负载均衡器中)。
默认情况下,eureka.instance.instanceId
是vcap.application.instance_id
,如以下示例所示:
eureka: instance: hostname: ${vcap.application.uris[0]} nonSecurePort: 80
根据在 Cloud Foundry 实例中设置安全规则的方式,您或许可以注册并使用主机 VM 的 IP 地址进行直接的服务到服务调用。 此功能在 Pivotal Web Services (PWS) 上尚不可用。
在 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;
}
更改 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
,如以下示例所示:
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 应用程序中自动填充,因此不需要 random 值。
使用 EurekaClient
一旦你有一个作为发现客户端的应用程序,就可以使用它从 Eureka 服务器发现服务实例。
一种方法是使用本机com.netflix.discovery.EurekaClient
(与 Spring Cloud 相反DiscoveryClient
),如以下示例所示:
@Autowired private EurekaClient discoveryClient; public String serviceUrl() { InstanceInfo instance = discoveryClient.getNextServerFromEureka("STORES", false); return instance.getHomePageUrl(); }
请勿使用 |
底层 HTTP 客户端
EurekaClient
使用RestTemplate
,WebClient
或JerseyClient
在引擎盖下。要使用EurekaClient
,您的 Classpath 上需要有一个受支持的 HTTP 客户端。
要使用RestTemplate
加spring-boot-starter-web
添加到您的依赖项中。要使用WebClient
加spring-boot-starter-webflux
添加到您的依赖项中。如果两者都RestTemplate
和WebClient
在 Classpath 上时eureka.client.webclient.enabled
设置为true
,WebClient
被使用。否则RestTemplate
被使用。
如果您希望改用 Jersey,则需要将 Jersey 依赖项添加到您的 Classpath 中。 以下示例显示了您需要添加的依赖项:
<dependencies>
<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>
</dependencies>
如果你有JerseyClient
在 Classpath 上,但不希望在EuerekaClient
,请确保将eureka.client.jersey.enabled
自false
.
本机 Netflix EurekaClient 的替代方案
您无需使用原始 NetflixEurekaClient
.
此外,在某种包装器后面使用它通常更方便。
Spring Cloud 通过逻辑 Eureka 服务标识符 (VIP) 而不是物理 URL 支持 Feign(一种 REST 客户端构建器)和 Spring Cloud LoadBalancer。
您还可以使用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; }
为什么注册服务这么慢?
作为实例还涉及对注册表的定期检测信号
(通过客户端的serviceUrl
),默认持续时间为 30 秒。
只有在实例、服务器和客户端的本地元数据中都具有相同的元数据后,客户端才能发现服务
cache (所以可能需要 3 次心跳)。
您可以通过设置eureka.instance.leaseRenewalIntervalInSeconds
.
将其设置为小于 30 的值可加快客户端连接到其他服务的过程。
在 生产环境中,最好坚持使用默认值,因为服务器中的内部计算会对租约续订期做出假设。
区
如果您已将 Eureka 客户端部署到多个区域,则可能希望这些客户端在尝试另一个区域中的服务之前使用同一区域中的服务。 要进行设置,您需要正确配置 Eureka 客户端。
首先,您需要确保已将 Eureka 服务器部署到每个区域,并且 他们是彼此的同伴。 有关更多信息,请参阅有关区域和区域的部分。
接下来,您需要告诉 Eureka 您的服务位于哪个区域。
您可以使用metadataMap
财产。
例如,如果service 1
部署到zone 1
和zone 2
,您需要在service 1
:
区域 1 中的服务 1
eureka.instance.metadataMap.zone = zone1
eureka.client.preferSameZoneEureka = true
区域 2 中的服务 1
eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true
刷新 Eureka 客户端
默认情况下,EurekaClient
bean 是可刷新的,这意味着可以更改和刷新 Eureka Client 端属性。
当刷新发生时,客户端将从 Eureka 服务器中注销,并且可能会有短暂的片刻
其中给定服务的所有实例都不可用。消除这种情况发生的一种方法是禁用
刷新 Eureka 客户端的能力。执行此作eureka.client.refresh.enable=false
.
将 Eureka 与 Spring Cloud LoadBalancer 一起使用
我们提供对 Spring Cloud LoadBalancer 的支持ZonePreferenceServiceInstanceListSupplier
.
这zone
Eureka 实例元数据 (eureka.instance.metadataMap.zone
) 用于设置
的值spring-cloud-loadbalancer-zone
属性,该属性用于按区域筛选服务实例。
如果缺少该选项,并且spring.cloud.loadbalancer.eureka.approximateZoneFromHostname
flag 设置为true
,
它可以使用服务器主机名中的域名作为区域的代理。
如果没有其他区域数据源,则根据客户端配置(而不是实例配置)进行猜测。
我们采取eureka.client.availabilityZones
,这是从区域名称到区域列表的映射,并提取实例自身区域的第一个区域(即eureka.client.region
,默认为“us-east-1”,以便与原生 Netflix 兼容)。
服务发现:Eureka Server
本节介绍如何设置 Eureka 服务器。
如何包含 Eureka 服务器
要将 Eureka Server 包含在您的项目中,请使用组 ID 为org.springframework.cloud
工件 ID 为spring-cloud-starter-netflix-eureka-server
.
有关使用当前 Spring Cloud Release Train 设置构建系统的详细信息,请参阅 Spring Cloud 项目页面。
如果您的项目已经使用 Thymeleaf 作为其模板引擎,则 Eureka 服务器的 Freemarker 模板可能无法正确加载。在这种情况下,需要手动配置模板加载器: |
spring: freemarker: template-loader-path: classpath:/templates/ prefer-file-system-access: false
如何运行 Eureka 服务器
以下示例显示了一个最小的 Eureka 服务器:
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(CustomerServiceTestApplication.class, args);
}
}
服务器有一个主页,其中包含用于常规 Eureka 功能的 UI 和 HTTP API 端点,位于/eureka/*
.
由于 Gradle 的依赖项解析规则和缺少父 bom 功能,具体取决于 build.gradle
|
defaultOpenForTrafficCount
及其对 EurekaServer 预热时间的影响
Netflix 尤里卡waitTimeInMsWhenSyncEmpty
设置在开始时不考虑 Spring Cloud Eureka 服务器。要启用预热时间,请将eureka.server.defaultOpenForTrafficCount=0
.
高可用性、区域和区域
Eureka 服务器没有后端存储,但是注册表中的服务实例都必须发送心跳以使其注册保持最新(因此可以在内存中完成)。 Client 端还具有 Eureka 注册的内存缓存(因此它们不必为对服务的每个请求都转到 registry)。
默认情况下,每个 Eureka 服务器也是一个 Eureka 客户端,并且需要(至少一个)服务 URL 来查找对等方。 如果您不提供它,该服务将运行并工作,但它会在您的日志中填充大量有关无法向对等方注册的噪音。
独立模式
两个缓存(客户端和服务器)和心跳的组合使独立的 Eureka 服务器对故障具有相当的弹性,只要有某种监视器或弹性运行时(例如 Cloud Foundry)使其保持活动状态。 在独立模式下,您可能更愿意关闭客户端行为,以便它不会不断尝试并无法访问其对等节点。 以下示例显示如何关闭客户端行为:
server: port: 8761 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
请注意,serviceUrl
指向与本地实例相同的主机。
对等体感知
通过运行多个实例并要求它们相互注册,可以使 Eureka 更具弹性和可用性。
事实上,这是默认行为,因此您需要做的就是添加一个有效的serviceUrl
对等体,如以下示例所示:
--- 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 文件,该文件可用于在两台主机上运行同一服务器 (peer1
和peer2
),方法是在不同的 Spring 配置文件中运行它。
您可以使用此配置通过纵来测试单个主机上的对等感知(在生产中这样做没有太大价值)/etc/hosts
解析主机名。
事实上,eureka.instance.hostname
如果您在知道自己的主机名的计算机上运行,则不需要(默认情况下,使用java.net.InetAddress
).
您可以将多个对等节点添加到系统中,并且只要它们都通过至少一个边缘相互连接,它们就会同步 他们之间的注册。 如果对等节点在物理上是分开的(在一个数据中心内或多个数据中心之间),那么系统原则上可以在“裂脑”类型的故障中幸存下来。 您可以向系统添加多个 Peer 节点,只要它们都是 它们将彼此直接连接,它们将同步 他们之间的注册。
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
何时首选 IP 地址
在某些情况下,Eureka 最好公布服务的 IP 地址而不是主机名。
设置eureka.instance.preferIpAddress
自true
而且,当应用程序向 Eureka 注册时,它会使用其 IP 地址而不是主机名。
如果 Java 无法确定主机名,则 IP 地址将发送到 Eureka。
设置主机名的唯一明确方法是设置 |
保护 Eureka 服务器
您只需将 Spring Security 添加到您的 Eureka 服务器中即可
服务器的 Classpath 通过spring-boot-starter-security
.默认情况下,当 Spring Security 位于 Classpath 上时,它将要求
向应用程序发送一个有效的 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 repo中找到演示 Eureka Server。
JDK 11 支持
Eureka 服务器所依赖的 JAXB 模块已在 JDK 11 中删除。如果您打算使用 JDK 11 运行 Eureka 服务器时,必须在 POM 或 Gradle 文件中包含这些依赖项。
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
指标
EurekaInstanceMonitor
侦听与 Eureka 实例注册相关的事件并创建/更新Gauge`s for Eureka instance information in Micrometer’s `MeterRegistry
.默认情况下,此行为处于禁用状态。如果要启用它,您需要设置eureka.server.metrics.enabled
自true
.
默认情况下,Gauge`s are named `eureka.server.instances
并具有以下标签:
-
application
:应用程序名称 -
status
: 实例状态 (UP
,DOWN
,STARTING
,OUT_OF_SERVICE
,UNKNOWN
看:com.netflix.appinfo.InstanceInfo.InstanceStatus
)
您可以通过注入自己的EurekaInstanceTagsProvider
.
配置属性
要查看所有 Spring Cloud Netflix 相关配置属性的列表,请查看附录页面。