云原生是一种应用程序开发风格,鼓励在持续交付和价值驱动开发领域轻松采用最佳实践。一个相关的学科是构建12 因素应用程序,其中开发实践与交付和运营目标保持一致 - 例如,通过使用声明性编程以及管理和监控。Spring Cloud 通过多种特定方式促进这些开发风格。出发点是分布式系统中的所有组件都需要轻松访问的一组功能。
其中许多功能都由Spring Cloud 构建的Spring Boot涵盖。Spring Cloud 作为两个库提供了更多功能:Spring Cloud Context 和 Spring Cloud Commons。ApplicationContextSpring Cloud Context为 Spring Cloud 应用程序提供实用程序和特殊服务(引导上下文、加密、刷新范围和环境端点)。Spring Cloud Commons 是不同 Spring Cloud 实现(例如 Spring Cloud Netflix 和 Spring Cloud Consul)中使用的一组抽象和通用类。
如果您因“非法密钥大小”而出现异常,并且您使用 Sun 的 JDK,则需要安装 Java 加密扩展 (JCE) 无限强度管辖策略文件。请参阅以下链接了解更多信息:
将文件提取到您使用的 JRE/JDK x64/x86 版本的 JDK/jre/lib/security 文件夹中。
| Spring Cloud 在非限制性 Apache 2.0 许可证下发布。如果您想为文档的这一部分做出贡献或者发现错误,您可以在 {docslink}[github] 上找到该项目的源代码和问题跟踪器。 |
1. Spring Cloud Context:应用程序上下文服务
Spring Boot 对于如何使用 Spring 构建应用程序有自己的看法。例如,它具有用于公共配置文件的常规位置,并具有用于公共管理和监视任务的端点。Spring Cloud 在此基础上构建,并添加了系统中许多组件会使用或偶尔需要的一些功能。
1.1. 引导程序应用程序上下文
Spring Cloud 应用程序通过创建“引导”上下文来运行,该上下文是主应用程序的父上下文。此上下文负责从外部源加载配置属性并解密本地外部配置文件中的属性。这两个上下文共享一个Environment,它是任何 Spring 应用程序的外部属性的来源。默认情况下,引导属性(不是bootstrap.properties在引导阶段加载的属性)以高优先级添加,因此它们不能被本地配置覆盖。
引导上下文使用与主应用程序上下文不同的约定来定位外部配置。您可以使用代替application.yml(或.properties),bootstrap.yml将引导程序的外部配置和主上下文很好地分开。以下清单显示了一个示例:
spring:
application:
name: foo
cloud:
config:
uri: ${SPRING_CONFIG_URI:http://localhost:8888}
如果您的应用程序需要来自服务器的任何特定于应用程序的配置,最好设置spring.application.name(inbootstrap.yml或application.yml)。spring.application.name对于要用作应用程序上下文 ID 的属性,您必须在 中设置它bootstrap.[properties | yml]。
如果您想检索特定的配置文件配置,您还应该spring.profiles.active在bootstrap.[properties | yml].
spring.cloud.bootstrap.enabled=false您可以通过设置(例如在系统属性中)完全禁用引导进程。
1.2. 应用程序上下文层次结构
SpringApplication如果您从或构建应用程序上下文SpringApplicationBuilder,则 Bootstrap 上下文将作为父上下文添加到该上下文。Spring 的一个功能是子上下文从其父上下文继承属性源和配置文件,因此与不使用 Spring Cloud Config 构建相同的上下文相比,“主”应用程序上下文包含额外的属性源。额外的财产来源是:
-
“bootstrap”:如果
PropertySourceLocators在引导上下文中找到任何内容并且它们具有非空属性,CompositePropertySource则会以高优先级显示可选内容。一个例子是来自 Spring Cloud Config Server 的属性。有关如何自定义此属性源的内容,请参阅“自定义 Bootstrap 属性源”。
在 Spring Cloud 2022.0.3 之前PropertySourceLocators(包括 Spring Cloud Config 的)是在主应用程序上下文中运行,而不是在 Bootstrap 上下文中运行。您可以通过设置强制在PropertySourceLocatorsBootstrap 上下文中运行。
spring.cloud.config.initialize-on-context-refresh=truebootstrap.[properties | yaml] |
-
“applicationConfig: [classpath:bootstrap.yml]”(以及相关文件,如果 Spring 配置文件处于活动状态):如果您有
bootstrap.yml(或.properties),则这些属性用于配置引导上下文。然后,当设置其父上下文时,它们将被添加到子上下文中。它们的优先级低于application.yml(或.properties) 以及作为创建 Spring Boot 应用程序过程的正常部分添加到子级的任何其他属性源。有关如何自定义这些属性源的内容,请参阅“更改 Bootstrap 属性的位置”。
由于属性源的排序规则,“bootstrap”条目优先。但请注意,它们不包含来自 的任何数据bootstrap.yml,该数据的优先级非常低,但可用于设置默认值。
您可以通过设置您创建的任何上下文的父上下文来扩展上下文层次结构ApplicationContext- 例如,通过使用其自己的接口或使用SpringApplicationBuilder便捷方法(parent()、child()和sibling())。引导上下文是您自己创建的最高级祖先的父级。层次结构中的每个上下文都有自己的“引导程序”(可能为空)属性源,以避免无意中将值从父母传递到其后代。如果有配置服务器,则层次结构中的每个上下文也可以(原则上)具有不同的spring.application.name,因此也可以具有不同的远程属性源。正常的 Spring 应用程序上下文行为规则适用于属性解析:子上下文中的属性按名称以及属性源名称覆盖父上下文中的属性。(如果子级具有与父级同名的属性源,则来自父级的值不会包含在子级中)。
请注意,它SpringApplicationBuilder允许您在整个层次结构中共享Environment,但这不是默认设置。因此,同级上下文(特别是)不需要具有相同的配置文件或属性源,即使它们可能与其父级共享共同的值。
1.3. 更改引导程序属性的位置
bootstrap.yml(或)位置.properties可以通过设置spring.cloud.bootstrap.name(默认:bootstrap)、spring.cloud.bootstrap.location(默认:空)或spring.cloud.bootstrap.additional-location(默认:空)来指定 - 例如,在系统属性中。
这些属性的行为类似于spring.config.*具有相同名称的变体。默认位置将被替换,并且spring.cloud.bootstrap.location仅使用指定的位置。spring.cloud.bootstrap.additional-location可以使用将位置添加到默认位置列表中。事实上,它们用于通过ApplicationContext在其Environment. 如果存在活动配置文件(来自spring.profiles.active或通过Environment您正在构建的上下文中的 API),该配置文件中的属性也会被加载,与常规 Spring Boot 应用程序中的属性相同 - 例如,来自配置bootstrap-development.properties文件development。
1.4. 覆盖远程属性的值
通过引导上下文添加到应用程序的属性源通常是“远程”的(例如,来自 Spring Cloud Config Server)。默认情况下,它们不能在本地被覆盖。如果您想让应用程序使用自己的系统属性或配置文件覆盖远程属性,则远程属性源必须通过设置授予其权限spring.cloud.config.allowOverride=true(在本地设置此设置不起作用)。设置该标志后,两个更细粒度的设置将控制远程属性相对于系统属性和应用程序本地配置的位置:
-
spring.cloud.config.overrideNone=true:从任何本地属性源覆盖。 -
spring.cloud.config.overrideSystemProperties=false:只有系统属性、命令行参数和环境变量(而不是本地配置文件)应该覆盖远程设置。
1.5. 自定义引导程序配置
/META-INF/spring.factories通过在名为 的键下添加条目,可以将引导上下文设置为执行任何您喜欢的操作org.springframework.cloud.bootstrap.BootstrapConfiguration。@Configuration它包含用于创建上下文的Spring 类的逗号分隔列表。您希望主应用程序上下文可用于自动装配的任何 bean 都可以在此处创建。有一个关于@Beansof 类型的特殊合同ApplicationContextInitializer。如果想控制启动顺序,可以用注解标记类@Order(默认顺序是last)。
添加 custom 时BootstrapConfiguration,请注意您添加的类不会被@ComponentScanned错误地添加到您的“主”应用程序上下文中,因为它们可能不需要。对启动配置类使用单独的包名称,并确保该名称尚未被您的@ComponentScan或@SpringBootApplication带注释的配置类覆盖。
|
引导过程通过将初始化程序注入主SpringApplication实例而结束(这是正常的 Spring Boot 启动序列,无论它作为独立应用程序运行还是部署在应用程序服务器中)。首先,从 中找到的类创建引导上下文spring.factories。然后,在启动之前,所有@Beans类型ApplicationContextInitializer都会添加到 main 中。SpringApplication
1.6. 自定义 Bootstrap 属性源
引导过程添加的外部配置的默认属性源是 Spring Cloud Config Server,但是您可以通过将 type 的 bean 添加PropertySourceLocator到引导上下文(通过spring.factories)来添加其他源。例如,您可以从不同的服务器或数据库插入其他属性。
作为示例,请考虑以下自定义定位器:
@Configuration
public class CustomPropertySourceLocator implements PropertySourceLocator {
@Override
public PropertySource<?> locate(Environment environment) {
return new MapPropertySource("customProperty",
Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
}
}
传入Environment的是即将创建的对象ApplicationContext- 换句话说,我们为其提供额外的属性源。它已经具有正常的 Spring Boot 提供的属性源,因此您可以使用它们来定位特定于此的属性源Environment(例如,通过将其键入spring.application.name,如默认的 Spring Cloud Config Server 属性源定位器中所做的那样)。
如果您创建一个包含此类的 jar,然后添加META-INF/spring.factories包含以下设置的 jar,则会customProperty PropertySource出现在其类路径中包含该 jar 的任何应用程序中:
org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator
从 Spring Cloud 2022.0.3 开始,Spring Cloud 现在将调用PropertySourceLocators两次。第一次获取将检索没有任何配置文件的任何属性源。这些财产来源将有机会使用 激活配置文件spring.profiles.active。主应用程序上下文启动后将PropertySourceLocators
被第二次调用,这次任何活动配置文件都允许PropertySourceLocators定位任何其他PropertySources配置文件。
1.7. 日志记录配置
如果您使用 Spring Boot 配置日志设置,bootstrap.[yml | properties]并且希望将其应用于所有事件,则应该将此配置放入其中。
为了让 Spring Cloud 正确初始化日志配置,您不能使用自定义前缀。例如,custom.loggin.logpath在初始化日志系统时,Spring Cloud 无法识别 using 。
|
1.8. 环境变化
EnvironmentChangeEvent应用程序以几种标准方式侦听更改并对更改做出反应(可以按照正常方式ApplicationListeners添加其他方式)。@Beans当观察到 an 时EnvironmentChangeEvent,它具有已更改的键值列表,并且应用程序使用这些值来:
-
重新绑定
@ConfigurationProperties上下文中的任何 bean。 -
设置 中任何属性的记录器级别
logging.level.*。
请注意,默认情况下,Spring Cloud Config Client 不会轮询Environment. 一般来说,我们不建议使用这种方法来检测更改(尽管您可以使用注释进行设置
@Scheduled)。如果您有一个横向扩展的客户端应用程序,最好将 广播EnvironmentChangeEvent到所有实例,而不是让它们轮询更改(例如,通过使用Spring Cloud Bus)。
它EnvironmentChangeEvent涵盖了大量的刷新用例,只要您可以实际对其进行更改Environment并发布事件即可。请注意,这些 API 是公共的,并且是 Spring 核心的一部分)。您可以通过访问端点(标准 Spring Boot Actuator 功能)来验证更改是否已绑定到@ConfigurationPropertiesbeans 。/configprops例如,aDataSource可以在运行时更改( Spring BootmaxPoolSize默认创建的是一个bean)并动态增加容量。重新绑定不涵盖另一大类用例,在这些用例中,您需要对刷新进行更多控制,并且需要对整个. 为了解决这些问题,我们有。DataSource@ConfigurationProperties@ConfigurationPropertiesApplicationContext@RefreshScope
1.9. 刷新范围
当配置发生更改时,@Bean标记为 的Spring@RefreshScope会得到特殊处理。此功能解决了有状态 Bean 仅在初始化时才注入配置的问题。例如,如果DataSource当数据库 URL 通过 更改时 a 有打开的连接Environment,您可能希望这些连接的持有者能够完成他们正在做的事情。然后,下次从池中借用连接时,它会获取带有新 URL 的连接。
有时,甚至可能必须@RefreshScope在某些只能初始化一次的 bean 上应用注释。如果 bean 是“不可变的”,则必须使用注释 bean@RefreshScope或在属性键下指定类名:spring.cloud.refresh.extra-refreshable。
如果您的DataSourcebean 是 a HikariDataSource,则无法刷新它。它是 的默认值spring.cloud.refresh.never-refreshable。DataSource如果您需要刷新,
请选择不同的实现。 |
刷新范围 bean 是惰性代理,在使用它们时(即调用方法时)进行初始化,并且范围充当初始化值的缓存。要强制 Bean 在下一个方法调用时重新初始化,您必须使其缓存条目无效。
它RefreshScope是上下文中的一个 bean,并且具有一个公共refreshAll()方法,可以通过清除目标缓存来刷新范围内的所有 bean。端点/refresh公开此功能(通过 HTTP 或 JMX)。要按名称刷新单个 bean,还有一种refresh(String)方法。
要公开/refresh端点,您需要将以下配置添加到您的应用程序:
management:
endpoints:
web:
exposure:
include: refresh
@RefreshScope(技术上)适用于一个@Configuration类,但它可能会导致令人惊讶的行为。例如,这并不意味着@Beans该类中定义的所有内容本身都在@RefreshScope. 具体来说,任何依赖于这些 bean 的东西都不能依赖它们在刷新启动时更新,除非它本身位于@RefreshScope. 在这种情况下,它会在刷新时重建,并重新注入其依赖项。此时,它们将从刷新的@Configuration) 中重新初始化。
|
| 删除配置值然后执行刷新不会更新配置值的存在。配置属性必须存在才能在刷新后更新值。如果您依赖应用程序中某个值的存在,您可能需要将逻辑切换为依赖该值的不存在。另一种选择是依赖值的更改,而不是不存在于应用程序的配置中。 |
1.10. 加密与解密
Spring Cloud 有一个Environment用于在本地解密属性值的预处理器。它遵循与 Spring Cloud Config Server 相同的规则,并通过encrypt.*. 因此,您可以使用 、 形式的加密值{cipher}*,并且只要存在有效密钥,它们就会在主应用程序上下文获取设置之前被解密Environment。要在应用程序中使用加密功能,您需要在类路径中包含 Spring Security RSA(Maven 坐标:org.springframework.security:spring-security-rsa),并且还需要 JVM 中的完整强度 JCE 扩展。
如果您因“非法密钥大小”而出现异常,并且您使用 Sun 的 JDK,则需要安装 Java 加密扩展 (JCE) 无限强度管辖策略文件。请参阅以下链接了解更多信息:
将文件提取到您使用的 JRE/JDK x64/x86 版本的 JDK/jre/lib/security 文件夹中。
1.11. 端点
对于 Spring Boot Actuator 应用程序,可以使用一些额外的管理端点。您可以使用:
-
POST更新并重新绑定/actuator/env和日志级别。要启用此端点,您必须设置。Environment@ConfigurationPropertiesmanagement.endpoint.env.post.enabled=true -
/actuator/refresh重新加载引导上下文并刷新@RefreshScopebean。 -
/actuator/restart关闭ApplicationContext并重新启动它(默认情况下禁用)。 -
/actuator/pause以及/actuator/resume调用Lifecycle方法(stop()和start())ApplicationContext。
虽然启用端点POST方法/actuator/env可以为管理应用程序环境变量提供灵活性和便利性,但确保端点受到保护和监视以防止潜在的安全风险至关重要。添加spring-boot-starter-security依赖项以配置执行器端点的访问控制。
|
如果禁用/actuator/restart端点,则/actuator/pause和/actuator/resume端点也将被禁用,因为它们只是 的特殊情况/actuator/restart。
|
2.Spring Cloud Commons:公共抽象
服务发现、负载均衡和断路器等模式提供了一个公共抽象层,所有 Spring Cloud 客户端都可以使用该抽象层,而与实现无关(例如,使用 Eureka 或 Consul 进行发现)。
2.1. 注释@EnableDiscoveryClient_
Spring Cloud Commons 提供了@EnableDiscoveryClient注释。这会查找 的实现DiscoveryClient以及ReactiveDiscoveryClient与 的接口META-INF/spring.factories。发现客户端的实现将配置类添加到密钥spring.factories下org.springframework.cloud.client.discovery.EnableDiscoveryClient。实现示例DiscoveryClient包括Spring Cloud Netflix Eureka、Spring Cloud Consul Discovery和Spring Cloud Zookeeper Discovery。
Spring Cloud 默认提供阻塞式和反应式服务发现客户端。spring.cloud.discovery.blocking.enabled=false您可以通过设置或轻松禁用阻塞和/或反应式客户端spring.cloud.discovery.reactive.enabled=false。要完全禁用服务发现,您只需设置spring.cloud.discovery.enabled=false.
默认情况下,实现将DiscoveryClient本地 Spring Boot 服务器自动注册到远程发现服务器。autoRegister=false可以通过设置来禁用此行为@EnableDiscoveryClient。
@EnableDiscoveryClient不再需要。您可以DiscoveryClient在类路径上放置一个实现,以使 Spring Boot 应用程序向服务发现服务器注册。
|
2.1.1. 健康指标
Commons 自动配置以下 Spring Boot 健康指标。
发现客户健康指标
该健康指标基于当前注册的DiscoveryClient实施。
-
要完全禁用,请设置
spring.cloud.discovery.client.health-indicator.enabled=false. -
要禁用描述字段,请设置
spring.cloud.discovery.client.health-indicator.include-description=false。description否则,它会随着卷起而冒泡HealthIndicator。 -
要禁用服务检索,请设置
spring.cloud.discovery.client.health-indicator.use-services-query=false。默认情况下,指标调用客户端的getServices方法。在具有许多注册服务的部署中,在每次检查期间检索所有服务的成本可能太高。这将跳过服务检索,而是使用客户端的probe方法。
DiscoveryCompositeHealth贡献者
该综合健康指标基于所有已注册的DiscoveryHealthIndicatorBean。要禁用,请设置spring.cloud.discovery.client.composite-indicator.enabled=false.
2.1.2. 订购DiscoveryClient实例
DiscoveryClient接口扩展Ordered。这在使用多个发现客户端时非常有用,因为它允许您定义返回的发现客户端的顺序,类似于对 Spring 应用程序加载的 bean 进行排序的方式。默认情况下,any 的顺序DiscoveryClient设置为
0。如果您想为自定义DiscoveryClient实现设置不同的顺序,您只需重写该getOrder()方法,以便它返回适合您的设置的值。除此之外,您还可以使用属性来设置Spring
Cloud等DiscoveryClient
提供的实现 的顺序。为此,您只需将
(或对于 Eureka)属性设置为所需的值。ConsulDiscoveryClientEurekaDiscoveryClientZookeeperDiscoveryClientspring.cloud.{clientIdentifier}.discovery.ordereureka.client.order
2.1.3. 简单发现客户端
DiscoveryClient如果类路径中没有 Service-Registry 支持的SimpleDiscoveryClient
实例,则将使用使用属性来获取有关服务和实例的信息的实例。
有关可用实例的信息应按以下格式通过属性传递:
spring.cloud.discovery.client.simple.instances.service1[0].uri=http://s11:8080,其中
spring.cloud.discovery.client.simple.instances是公共前缀,然后service1代表相关服务的 ID,而[0]表示实例的索引号(如示例中所示,索引以0) 开头,然后 的值uri是实例可用的实际 URI。
2.2. 服务注册中心
Commons 现在提供了一个接口,该接口提供了和ServiceRegistry等方法,使您可以提供自定义注册服务。
是一个标记接口。register(Registration)deregister(Registration)Registration
以下示例显示了ServiceRegistry使用中的情况:
@Configuration
@EnableDiscoveryClient(autoRegister=false)
public class MyConfiguration {
private ServiceRegistry registry;
public MyConfiguration(ServiceRegistry registry) {
this.registry = registry;
}
// called through some external process, such as an event or a custom actuator endpoint
public void register() {
Registration registration = constructRegistration();
this.registry.register(registration);
}
}
每个ServiceRegistry实现都有自己的Registry实现。
-
ZookeeperRegistration与...一起使用ZookeeperServiceRegistry -
EurekaRegistration与...一起使用EurekaServiceRegistry -
ConsulRegistration与...一起使用ConsulServiceRegistry
如果您使用该ServiceRegistry接口,则需要Registry为您正在使用的实现传递正确的实现ServiceRegistry。
2.2.1. ServiceRegistry自动注册
默认情况下,该ServiceRegistry实现会自动注册正在运行的服务。要禁用该行为,您可以设置: *@EnableDiscoveryClient(autoRegister=false)以永久禁用自动注册。*spring.cloud.service-registry.auto-registration.enabled=false通过配置禁用该行为。
ServiceRegistry 自动注册事件
服务自动注册时将触发两个事件。第一个事件称为
InstancePreRegisteredEvent,在服务注册之前触发。第二个事件称为InstanceRegisteredEvent,在服务注册后触发。您可以注册一个
ApplicationListener(s)来监听这些事件并做出反应。
spring.cloud.service-registry.auto-registration.enabled如果该属性设置为 ,
则不会触发这些事件false。
|
2.2.2. 服务注册表执行器端点
Spring Cloud Commons 提供了一个/service-registry执行器端点。该端点依赖于RegistrationSpring 应用程序上下文中的 bean。使用/service-registryGET 调用会返回Registration. 使用 POST 到同一端点并使用 JSON 正文将当前状态更改Registration为新值。JSON 正文必须包含status具有首选值的字段。ServiceRegistry请参阅您在更新状态时使用的允许值以及状态返回值的实现文档。例如,Eureka 支持的状态有UP、DOWN、OUT_OF_SERVICE、 和UNKNOWN。
2.3. Spring RestTemplate 作为负载均衡器客户端
您可以配置RestTemplate使用负载平衡器客户端。要创建负载平衡RestTemplate,请创建RestTemplate @Bean并使用@LoadBalanced限定符,如以下示例所示:
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
public String doOtherStuff() {
String results = restTemplate.getForObject("http://stores/stores", String.class);
return results;
}
}
beanRestTemplate不再通过自动配置创建。单独的应用程序必须创建它。
|
URI需要使用虚拟主机名(即服务名,而不是主机名)。BlockingLoadBalancerClient 用于创建完整的物理地址。
要使用负载平衡RestTemplate,您需要在类路径中实现负载平衡器。将Spring Cloud LoadBalancer starter添加到您的项目中以便使用它。
|
2.4. Spring WebClient 作为负载均衡器客户端
您可以配置WebClient为自动使用负载平衡器客户端。要创建负载平衡WebClient,请创建WebClient.Builder @Bean并使用@LoadBalanced限定符,如下所示:
@Configuration
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
public Mono<String> doOtherStuff() {
return webClientBuilder.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
}
URI需要使用虚拟主机名(即服务名,而不是主机名)。Spring Cloud LoadBalancer 用于创建完整的物理地址。
如果要使用@LoadBalanced WebClient.Builder,则需要在类路径中实现负载均衡器。我们建议您将
Spring Cloud LoadBalancer 启动器添加到您的项目中。然后,ReactiveLoadBalancer在下面使用。
|
2.4.1. 重试失败的请求
负载平衡RestTemplate可以配置为重试失败的请求。默认情况下,此逻辑被禁用。对于非反应式版本(带有RestTemplate),您可以通过将Spring Retry添加到应用程序的类路径来启用它。对于反应式版本(带有WebTestClient),您需要设置spring.cloud.loadbalancer.retry.enabled=true。
如果您想在类路径上使用 Spring Retry 或 Reactive Retry 禁用重试逻辑,您可以设置spring.cloud.loadbalancer.retry.enabled=false.
对于非响应式实现,如果您想BackOffPolicy在重试中实现 a,则需要创建一个类型的 beanLoadBalancedRetryFactory并重写该createBackOffPolicy()方法。
对于反应式实现,您只需通过设置为spring.cloud.loadbalancer.retry.backoff.enabled来启用它false。
您可以设置:
-
spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance- 指示应在同一请求上重试多少次ServiceInstance(为每个选定的实例单独计数) -
spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance- 指示新选择的请求应重试多少次ServiceInstance -
spring.cloud.loadbalancer.retry.retryableStatusCodes- 始终重试失败请求的状态代码。
对于反应式实现,您还可以设置: - spring.cloud.loadbalancer.retry.backoff.minBackoff- 设置最小退避持续时间(默认情况下,5 毫秒) - spring.cloud.loadbalancer.retry.backoff.maxBackoff- 设置最大退避持续时间(默认情况下,最大毫秒长值) - spring.cloud.loadbalancer.retry.backoff.jitter- 设置用于计算抖动的抖动每次调用的实际退避持续时间(默认为 0.5)。
对于反应式实现,您还可以实现自己的实现,LoadBalancerRetryPolicy以对负载平衡调用重试进行更详细的控制。
对于这两种实现,您还可以通过在属性下添加值列表来设置触发回复的异常spring.cloud.loadbalancer.[serviceId].retry.retryable-exceptions。如果您这样做,我们确保添加RetryableStatusCodeExceptions到您提供的异常列表中,以便我们也重试可重试的状态代码。如果您没有通过属性指定任何异常,则我们默认使用的异常是IOException,TimeoutException和RetryableStatusCodeException。您还可以通过设置spring.cloud.loadbalancer.[serviceId].retry.retry-on-all-exceptions为 来启用对所有异常的重试true。
如果您将阻塞实现与 Spring Retries 一起使用,如果您想保留以前版本的行为,请设置spring.cloud.loadbalancer.[serviceId].retry.retry-on-all-exceptions为true阻塞实现的默认模式。
|
spring.cloud.loadbalancer.clients.<clientId>.*可以使用与上述相同的属性单独配置各个负载均衡器客户端,除了
前缀是clientId负载均衡器的名称。
|
对于负载平衡重试,默认情况下,我们会包装ServiceInstanceListSupplierbean,RetryAwareServiceInstanceListSupplier以选择与之前选择的实例不同的实例(如果可用)。spring.cloud.loadbalancer.retry.avoidPreviousInstance您可以通过将的值设置为 来禁用此行为false。
|
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryFactory retryFactory() {
return new LoadBalancedRetryFactory() {
@Override
public BackOffPolicy createBackOffPolicy(String service) {
return new ExponentialBackOffPolicy();
}
};
}
}
如果要向RetryListener重试功能添加一个或多个实现,则需要创建一个 类型的 beanLoadBalancedRetryListenerFactory并返回RetryListener要用于给定服务的数组,如以下示例所示:
@Configuration
public class MyConfiguration {
@Bean
LoadBalancedRetryListenerFactory retryListenerFactory() {
return new LoadBalancedRetryListenerFactory() {
@Override
public RetryListener[] createRetryListeners(String service) {
return new RetryListener[]{new RetryListener() {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
//TODO Do you business...
return true;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
//TODO Do you business...
}
}};
}
};
}
}
2.5. 多个RestTemplate对象
如果您想要一个RestTemplate非负载平衡的,请创建一个RestTemplatebean 并注入它。要访问 load-balanced RestTemplate,请@LoadBalanced在创建 时使用限定符@Bean,如以下示例所示:
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
RestTemplate loadBalanced() {
return new RestTemplate();
}
@Primary
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
@Autowired
@LoadBalanced
private RestTemplate loadBalanced;
public String doOtherStuff() {
return loadBalanced.getForObject("http://stores/stores", String.class);
}
public String doStuff() {
return restTemplate.getForObject("http://example.com", String.class);
}
}
@Primary请注意前面示例中在普通声明上
使用注释来RestTemplate消除不合格@Autowired注入的歧义。
|
如果您看到诸如此类的错误java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89,请尝试注入RestOperations或设置spring.aop.proxyTargetClass=true。
|
2.6。多个 WebClient 对象
如果您想要一个WebClient非负载平衡的,请创建一个WebClientbean 并注入它。要访问 load-balanced WebClient,请@LoadBalanced在创建 时使用限定符@Bean,如以下示例所示:
@Configuration
public class MyConfiguration {
@LoadBalanced
@Bean
WebClient.Builder loadBalanced() {
return WebClient.builder();
}
@Primary
@Bean
WebClient.Builder webClient() {
return WebClient.builder();
}
}
public class MyClass {
@Autowired
private WebClient.Builder webClientBuilder;
@Autowired
@LoadBalanced
private WebClient.Builder loadBalanced;
public Mono<String> doOtherStuff() {
return loadBalanced.build().get().uri("http://stores/stores")
.retrieve().bodyToMono(String.class);
}
public Mono<String> doStuff() {
return webClientBuilder.build().get().uri("http://example.com")
.retrieve().bodyToMono(String.class);
}
}
2.7. Spring WebFluxWebClient作为负载均衡器客户端
Spring WebFlux 可以使用反应式和非反应式WebClient配置,如主题所述:
2.7.1. Spring WebFluxWebClient与ReactorLoadBalancerExchangeFilterFunction
您可以配置WebClient为使用ReactiveLoadBalancer. 如果将Spring Cloud LoadBalancer 启动器添加到项目中并且spring-webflux位于类路径上,ReactorLoadBalancerExchangeFilterFunction则会自动配置。以下示例显示如何配置WebClient使用反应式负载均衡器:
public class MyClass {
@Autowired
private ReactorLoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URI需要使用虚拟主机名(即服务名,而不是主机名)。用于ReactorLoadBalancer创建完整的物理地址。
2.7.2. WebClient带有非反应式负载均衡器客户端的Spring WebFlux
如果spring-webflux位于类路径上,LoadBalancerExchangeFilterFunction
则为自动配置。但请注意,这在幕后使用了非响应式客户端。以下示例显示如何配置WebClient使用负载均衡器:
public class MyClass {
@Autowired
private LoadBalancerExchangeFilterFunction lbFunction;
public Mono<String> doOtherStuff() {
return WebClient.builder().baseUrl("http://stores")
.filter(lbFunction)
.build()
.get()
.uri("/stores")
.retrieve()
.bodyToMono(String.class);
}
}
URI需要使用虚拟主机名(即服务名,而不是主机名)。用于LoadBalancerClient创建完整的物理地址。
警告:此方法现已弃用。我们建议您使用带有反应式负载均衡器的 WebFlux 。
2.8. 忽略网络接口
有时,忽略某些命名网络接口很有用,以便将它们排除在服务发现注册之外(例如,在 Docker 容器中运行时)。可以设置正则表达式列表来忽略所需的网络接口。以下配置忽略该docker0接口以及所有以 开头的接口veth:
spring:
cloud:
inetutils:
ignoredInterfaces:
- docker0
- veth.*
您还可以通过使用正则表达式列表强制仅使用指定的网络地址,如以下示例所示:
spring:
cloud:
inetutils:
preferredNetworks:
- 192.168
- 10.0
您还可以强制仅使用站点本地地址,如以下示例所示:
spring:
cloud:
inetutils:
useOnlySiteLocalInterfaces: true
有关站点本地地址的构成的更多详细信息,请参阅Inet4Address.html.isSiteLocalAddress() 。
2.9. HTTP 客户端工厂
Spring Cloud Commons 提供了用于创建 Apache HTTP 客户端 ( ApacheHttpClientFactory) 和 OK HTTP 客户端 ( OkHttpClientFactory) 的 bean。OkHttpClientFactory仅当 OK HTTP jar 位于类路径上时才会创建 bean 。此外,Spring Cloud Commons 还提供了用于创建两个客户端使用的连接管理器的 bean:ApacheHttpClientConnectionManagerFactoryApache HTTP 客户端和OkHttpClientConnectionPoolFactoryOK HTTP 客户端。如果您想自定义在下游项目中创建 HTTP 客户端的方式,您可以提供您自己的这些 bean 实现。此外,如果您提供HttpClientBuilder或类型的 bean OkHttpClient.Builder,默认工厂将使用这些构建器作为返回下游项目的构建器的基础。spring.cloud.httpclientfactories.apache.enabled您还可以通过设置或spring.cloud.httpclientfactories.ok.enabled来禁用这些 bean 的创建false。
2.10. 启用的功能
Spring Cloud Commons 提供了一个/features执行器端点。此端点返回类路径上可用的功能以及它们是否已启用。返回的信息包括功能类型、名称、版本和供应商。
2.10.1. 特征类型
“特征”有两种类型:抽象特征和命名特征。
抽象功能是定义接口或抽象类并创建实现的功能,例如DiscoveryClient、LoadBalancerClient或LockService。抽象类或接口用于在上下文中查找该类型的 bean。显示的版本是bean.getClass().getPackage().getImplementationVersion().
命名功能是没有实现特定类的功能。这些功能包括“Circuit Breaker”、“API Gateway”、“Spring Cloud Bus”等。这些功能需要名称和 bean 类型。
2.10.2. 声明功能
任何模块都可以声明任意数量的HasFeaturebean,如以下示例所示:
@Bean
public HasFeatures commonsFeatures() {
return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class);
}
@Bean
public HasFeatures consulFeatures() {
return HasFeatures.namedFeatures(
new NamedFeature("Spring Cloud Bus", ConsulBusAutoConfiguration.class),
new NamedFeature("Circuit Breaker", HystrixCommandAspect.class));
}
@Bean
HasFeatures localFeatures() {
return HasFeatures.builder()
.abstractFeature(Something.class)
.namedFeature(new NamedFeature("Some Other Feature", Someother.class))
.abstractFeature(Somethingelse.class)
.build();
}
这些豆子中的每一个都应该受到适当的保护@Configuration。
2.11. Spring Cloud兼容性验证
由于一些用户在设置Spring Cloud应用程序时遇到问题,我们决定添加兼容性验证机制。如果您当前的设置与 Spring Cloud 要求不兼容,它将崩溃,并附上一份报告,显示到底出了什么问题。
目前,我们验证哪个版本的 Spring Boot 已添加到您的类路径中。
报告示例
*************************** APPLICATION FAILED TO START *************************** Description: Your project setup is incompatible with our requirements due to following reasons: - Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train Action: Consider applying the following actions: - Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] . You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn]. If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.
要禁用此功能,请设置spring.cloud.compatibility-verifier.enabled为false。如果要覆盖兼容的 Spring Boot 版本,只需
spring.cloud.compatibility-verifier.compatible-boot-versions使用逗号分隔的兼容 Spring Boot 版本列表设置该属性即可。
3. Spring Cloud负载均衡器
Spring Cloud 提供了自己的客户端负载均衡器抽象和实现。对于负载均衡机制,ReactiveLoadBalancer添加了接口,并提供了基于循环和随机的实现。为了让实例能够从反应式中ServiceInstanceListSupplier
进行选择。目前,我们支持基于服务发现的实现,该实现使用类路径中可用的发现客户端ServiceInstanceListSupplier
从服务发现中检索可用实例。
可以通过将 的值设置为 来禁用 Spring Cloud spring.cloud.loadbalancer.enabledLoadBalancer false。
|
3.1. LoadBalancer 上下文的预加载
Spring Cloud LoadBalancer 为每个服务 id 创建一个单独的 Spring 子上下文。默认情况下,每当对服务 ID 的第一个请求进行负载平衡时,这些上下文都会被延迟初始化。
您可以选择立即加载这些上下文。为此,请使用该spring.cloud-loadbalancer.eager-load.clients属性指定要为其执行预加载的服务 ID。
3.2. 负载均衡算法之间的切换
ReactiveLoadBalancer默认使用的实现是RoundRobinLoadBalancer. 要切换到不同的实现(对于选定的服务或所有服务),您可以使用自定义 LoadBalancer 配置机制。
例如,可以通过@LoadBalancerClient注释传递以下配置以切换到使用RandomLoadBalancer:
public class CustomLoadBalancerConfiguration {
@Bean
ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
}
您作为参数传递的类@LoadBalancerClient或@LoadBalancerClients配置参数不应带有注释@Configuration或位于组件扫描范围之外。
|
3.3. Spring Cloud 负载均衡器集成
为了方便使用 Spring Cloud LoadBalancer,我们提供了ReactorLoadBalancerExchangeFilterFunctioncan be use withWebClient和BlockingLoadBalancerClientthat Works with RestTemplate. 您可以在以下部分中查看更多信息和使用示例:
3.4. Spring Cloud LoadBalancer 缓存
除了每次必须选择实例时ServiceInstanceListSupplier检索实例的基本实现之外,我们还提供了两种缓存实现。DiscoveryClient
3.4.1. Caffeine支持的 LoadBalancer 缓存实现
如果类路径中有com.github.ben-manes.caffeine:caffeine,则将使用基于咖啡因的实现。有关如何配置它的信息,请参阅LoadBalancerCacheConfiguration部分。
如果您使用 Caffeine,您还可以通过在属性中传递您自己的Caffeine 规范来覆盖 LoadBalancer 的默认 Caffeine 缓存设置spring.cloud.loadbalancer.cache.caffeine.spec。
警告:传递您自己的 Caffeine 规范将覆盖任何其他 LoadBalancerCache 设置,包括常规 LoadBalancer 缓存配置字段,例如ttl和capacity。
3.4.2. 默认 LoadBalancer 缓存实现
如果类路径中没有 Caffeine,则将使用DefaultLoadBalancerCache自动附带的。有关如何配置它的信息,spring-cloud-starter-loadbalancer请参阅LoadBalancerCacheConfiguration部分。
要使用 Caffeine 而不是默认缓存,请将com.github.ben-manes.caffeine:caffeine依赖项添加到类路径。
|
3.4.3. 负载均衡器缓存配置
您可以通过传递符合Spring Boot 的转换器语法来设置自己的ttl值(写入后的时间,在此之后条目应过期),表示为。作为财产的价值。您还可以通过设置该属性的值来设置自己的LoadBalancer缓存初始容量。DurationStringStringDurationspring.cloud.loadbalancer.cache.ttlspring.cloud.loadbalancer.cache.capacity
默认设置包括ttl设置为 35 秒,默认initialCapacity值为256。
spring.cloud.loadbalancer.cache.enabled
您还可以通过设置to的值来完全禁用 loadBalancer 缓存false。
尽管基本的非缓存实现对于原型设计和测试很有用,但它的效率比缓存版本低得多,因此我们建议在生产中始终使用缓存版本。DiscoveryClient例如,如果实现已完成缓存EurekaDiscoveryClient,则应禁用负载平衡器缓存以防止双重缓存。
|
当您创建自己的配置时,如果您使用,CachingServiceInstanceListSupplier请确保将其直接放置在层次结构中通过网络检索实例的供应商之后(例如 ),DiscoveryClientServiceInstanceListSupplier位于任何其他过滤供应商之前。
|
3.5. 加权负载平衡
为了启用加权负载平衡,我们提供了WeightedServiceInstanceListSupplier. 我们用来WeightFunction计算每个实例的权重。默认情况下,我们尝试从元数据映射中读取并解析权重(关键是weight)。
如果元数据映射中没有指定权重,我们默认该实例的权重为1。
spring.cloud.loadbalancer.configurations您可以通过设置to的值weighted或提供您自己的ServiceInstanceListSupplierbean 来配置它,例如:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withWeighted()
.withCaching()
.build(context);
}
}
您还可以通过提供自定义权重计算逻辑WeightFunction。
|
您可以使用此示例配置使所有实例具有随机权重:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withWeighted(instance -> ThreadLocalRandom.current().nextInt(1, 101))
.withCaching()
.build(context);
}
}
3.6. 基于区域的负载平衡
为了启用基于区域的负载平衡,我们提供了ZonePreferenceServiceInstanceListSupplier. 我们使用DiscoveryClient-特定zone配置(例如,eureka.instance.metadata-map.zone)来选择客户端尝试过滤可用服务实例的区域。
您还可以DiscoveryClient通过设置属性值来覆盖特定区域设置spring.cloud.loadbalancer.zone。
|
目前,仅使用 Eureka Discovery 客户端来设置 LoadBalancer 区域。对于其他发现客户端,设置该spring.cloud.loadbalancer.zone属性。更多仪器即将推出。
|
为了确定检索到的区域,我们检查其元数据映射中键
ServiceInstance下的值。"zone" |
过滤ZonePreferenceServiceInstanceListSupplier器检索实例并仅返回同一区域内的实例。如果该区域是null或同一区域内不存在实例,则返回所有检索到的实例。
为了使用基于区域的负载平衡方法,您必须在自定义配置ZonePreferenceServiceInstanceListSupplier中实例化一个bean 。
我们使用委托来处理ServiceInstanceListSupplierbean。我们建议使用DiscoveryClientServiceInstanceListSupplier委托,将其包装起来以CachingServiceInstanceListSupplier利用LoadBalancer 缓存机制,然后将生成的 bean 传递到 的构造函数中ZonePreferenceServiceInstanceListSupplier。
您可以使用此示例配置来进行设置:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withCaching()
.withZonePreference()
.build(context);
}
}
3.7. LoadBalancer 的实例健康检查
可以为 LoadBalancer 启用计划的运行状况检查。为此HealthCheckServiceInstanceListSupplier
提供了 。它定期验证委托提供的实例是否
ServiceInstanceListSupplier仍然存在,并且只返回健康的实例,除非没有 - 然后它返回所有检索到的实例。
该机制在使用SimpleDiscoveryClient. 对于由实际服务注册表支持的客户端,没有必要使用它,因为我们在查询外部 ServiceDiscovery 后已经获得了健康的实例。
|
| 还建议将此供应商设置为每个服务具有少量实例,以避免在失败的实例上重试调用。 |
| 如果使用任何服务发现支持的供应商,通常不需要添加此运行状况检查机制,因为我们直接从服务注册表检索实例的运行状况。 |
这HealthCheckServiceInstanceListSupplier依赖于委托通量提供的更新实例。在极少数情况下,当您想要使用不刷新实例的委托时,即使实例列表可能发生变化(例如我们提供的)DiscoveryClientServiceInstanceListSupplier,您可以设置spring.cloud.loadbalancer.health-check.refetch-instances为true让实例列表由HealthCheckServiceInstanceListSupplier. 然后,您还可以通过修改 的值来调整重新刷新间隔,并选择通过spring.cloud.loadbalancer.health-check.refetch-instances-interval设置为禁用额外的运行状况检查重复,因为每个实例重新获取也会触发运行状况检查。
spring.cloud.loadbalancer.health-check.repeat-health-checkfalse |
HealthCheckServiceInstanceListSupplier使用前缀为 . 的属性
spring.cloud.loadbalancer.health-check。
您可以为调度程序设置initialDelay和。interval您可以通过设置该属性的值来设置运行状况检查 URL 的默认路径spring.cloud.loadbalancer.health-check.path.default。您还可以通过设置属性值来为任何给定服务设置特定值spring.cloud.loadbalancer.health-check.path.[SERVICE_ID],并替换[SERVICE_ID]为正确的服务 ID。如果[SERVICE_ID]未指定,/actuator/health则默认使用。如果[SERVICE_ID]设置为null或空作为值,则不会执行健康检查。您还可以通过设置 的值来为运行状况检查请求设置自定义端口spring.cloud.loadbalancer.health-check.port。如果未设置,则请求的服务在服务实例上可用的端口。
如果您依赖于默认路径 ( /actuator/health),请确保添加spring-boot-starter-actuator到协作者的依赖项,除非您计划自己添加此类端点。
|
默认情况下,将在已检索到的healthCheckFlux每个活动上发出。您可以通过将ServiceInstance的值设置为 来修改此行为。如果此属性设置为,则首先将整个活动实例序列收集到列表中,然后才发出,这确保通量不会在属性中设置的运行状况检查间隔之间发出值。
spring.cloud.loadbalancer.health-check.update-results-listfalsefalse |
为了使用运行状况检查调度程序方法,您必须在自定义配置HealthCheckServiceInstanceListSupplier中实例化一个bean 。
我们使用委托来处理ServiceInstanceListSupplierbean。DiscoveryClientServiceInstanceListSupplier我们建议在 的构造函数中传递一个委托HealthCheckServiceInstanceListSupplier。
您可以使用此示例配置来进行设置:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withHealthChecks()
.build(context);
}
}
对于非反应式堆栈,请使用withBlockingHealthChecks(). 您还可以传递您自己的实例WebClient或RestTemplate实例以用于检查。
|
HealthCheckServiceInstanceListSupplier有自己的基于 Reactor Flux 的缓存机制replay()。因此,如果正在使用它,您可能需要跳过用CachingServiceInstanceListSupplier.
|
当您创建自己的配置 时,HealthCheckServiceInstanceListSupplier请确保将其直接放置在层次结构中通过网络检索实例的供应商之后(例如,位于DiscoveryClientServiceInstanceListSupplier任何其他过滤供应商之前)。
|
3.8. LoadBalancer 的相同实例首选项
您可以设置 LoadBalancer,使其优先选择之前选择的实例(如果该实例可用)。
为此,您需要使用SameInstancePreferenceServiceInstanceListSupplier. spring.cloud.loadbalancer.configurations您可以通过设置to的值same-instance-preference或提供您自己的ServiceInstanceListSupplierbean 来配置它 - 例如:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withSameInstancePreference()
.build(context);
}
}
这也是 Zookeeper 的替代品StickyRule。
|
3.9. LoadBalancer 基于请求的粘性会话
您可以设置 LoadBalancer,使其更喜欢instanceId请求 cookie 中提供的实例。ClientRequestContext如果请求通过或传递到 LoadBalancer,我们目前支持此功能ServerHttpRequestContext,SC LoadBalancer 交换过滤器函数和过滤器使用 或 。
为此,您需要使用RequestBasedStickySessionServiceInstanceListSupplier. spring.cloud.loadbalancer.configurations您可以通过设置to的值request-based-sticky-session或提供您自己的ServiceInstanceListSupplierbean 来配置它 - 例如:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withRequestBasedStickySession()
.build(context);
}
}
对于该功能,在转发请求之前更新选定的服务实例(如果原始请求 cookie 中的服务实例不可用,则该实例可能与原始请求 cookie 中的服务实例不同)很有用。为此,请将 的值设置spring.cloud.loadbalancer.sticky-session.add-service-instance-cookie为true。
默认情况下,cookie 的名称是sc-lb-instance-id。您可以通过更改属性的值来修改它spring.cloud.loadbalancer.instance-id-cookie-name。
| 目前,WebClient 支持的负载平衡支持此功能。 |
3.10. Spring Cloud LoadBalancer 提示
Spring Cloud LoadBalancer 允许您设置String传递给对象内的 LoadBalancer 的提示,并且稍后可以在可以处理它们的实现Request中使用这些提示。ReactiveLoadBalancer
您可以通过设置属性的值来为所有服务设置默认提示spring.cloud.loadbalancer.hint.default。您还可以通过设置属性值来为任何给定服务设置特定值spring.cloud.loadbalancer.hint.[SERVICE_ID],并替换[SERVICE_ID]为正确的服务 ID。如果用户未设置提示,default则使用。
3.11. 基于提示的负载平衡
我们还提供了一个HintBasedServiceInstanceListSupplier,它是ServiceInstanceListSupplier基于提示的实例选择的实现。
HintBasedServiceInstanceListSupplier检查提示请求标头(默认标头名称为X-SC-LB-Hint,但您可以通过更改属性值来修改它spring.cloud.loadbalancer.hint-header-name),如果找到提示请求标头,则使用标头中传递的提示值来过滤服务实例。
如果未添加提示标头,HintBasedServiceInstanceListSupplier则使用属性中的提示值来过滤服务实例。
如果未通过标头或属性设置提示,则返回委托提供的所有服务实例。
过滤时,HintBasedServiceInstanceListSupplier查找hint在其metadataMap. 如果没有找到匹配的实例,则返回委托提供的所有实例。
您可以使用以下示例配置来进行设置:
public class CustomLoadBalancerConfiguration {
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withCaching()
.withHints()
.build(context);
}
}
3.12. 转换负载平衡的 HTTP 请求
您可以使用所选内容ServiceInstance来转换负载平衡的 HTTP 请求。
对于RestTemplate,您需要实现并定义LoadBalancerRequestTransformer如下:
@Bean
public LoadBalancerRequestTransformer transformer() {
return new LoadBalancerRequestTransformer() {
@Override
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
return new HttpRequestWrapper(request) {
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.putAll(super.getHeaders());
headers.add("X-InstanceId", instance.getInstanceId());
return headers;
}
};
}
};
}
对于WebClient,您需要实现并定义LoadBalancerClientRequestTransformer如下:
@Bean
public LoadBalancerClientRequestTransformer transformer() {
return new LoadBalancerClientRequestTransformer() {
@Override
public ClientRequest transformRequest(ClientRequest request, ServiceInstance instance) {
return ClientRequest.from(request)
.header("X-InstanceId", instance.getInstanceId())
.build();
}
};
}
如果定义了多个转换器,它们将按照定义 Bean 的顺序应用。或者,您可以使用LoadBalancerRequestTransformer.DEFAULT_ORDER或LoadBalancerClientRequestTransformer.DEFAULT_ORDER来指定顺序。
3.13. Spring Cloud LoadBalancer 入门
我们还提供了一个启动器,允许您在 Spring Boot 应用程序中轻松添加 Spring Cloud LoadBalancer。为了使用它,只需org.springframework.cloud:spring-cloud-starter-loadbalancer在构建文件中添加 Spring Cloud 依赖项即可。
| Spring Cloud LoadBalancer 启动器包括 Spring Boot Caching 和Evictor。 |
3.14。传递您自己的 Spring Cloud LoadBalancer 配置
您还可以使用@LoadBalancerClient注释来传递您自己的负载均衡器客户端配置,传递负载均衡器客户端的名称和配置类,如下所示:
@Configuration
@LoadBalancerClient(value = "stores", configuration = CustomLoadBalancerConfiguration.class)
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
为了使您自己的 LoadBalancer 配置更容易,我们builder()向该类添加了一个方法ServiceInstanceListSupplier。
|
spring.cloud.loadbalancer.configurations您还可以通过将属性值设置为zone-preferenceto use ZonePreferenceServiceInstanceListSupplierwith caching 或 to health-checkto use HealthCheckServiceInstanceListSupplierwith caching,
使用我们的替代预定义配置来代替默认配置。 |
您可以使用此功能实例化ServiceInstanceListSupplier或的不同实现ReactorLoadBalancer,可以由您编写,也可以由我们提供作为替代方案(例如ZonePreferenceServiceInstanceListSupplier)来覆盖默认设置。
您可以在此处查看自定义配置的示例。
注释value参数(stores在上面的示例中)指定我们应该使用给定的自定义配置将请求发送到的服务的服务 ID。
|
您还可以通过注释传递多个配置(针对多个负载均衡器客户端)@LoadBalancerClients,如以下示例所示:
@Configuration
@LoadBalancerClients({@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = "customers", configuration = CustomersLoadBalancerClientConfiguration.class)})
public class MyConfiguration {
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}
您作为参数传递的类@LoadBalancerClient或@LoadBalancerClients配置参数不应带有注释@Configuration或位于组件扫描范围之外。
|
当您创建自己的配置时,如果您使用CachingServiceInstanceListSupplier或HealthCheckServiceInstanceListSupplier,请确保使用其中之一,而不是同时使用两者,并确保将其直接放在通过网络检索实例的供应商之后的层次结构中,例如,在任何DiscoveryClientServiceInstanceListSupplier之前其他过滤供应商。
|
3.15。Spring Cloud LoadBalancer 生命周期
使用自定义 LoadBalancer 配置注册可能有用的一种 bean 类型是LoadBalancerLifecycle。
这些bean 提供名为、和 的LoadBalancerLifecycle回调方法,您应该实现这些方法来指定在负载平衡之前和之后应执行哪些操作。onStart(Request<RC> request)onStartRequest(Request<RC> request, Response<T> lbResponse)onComplete(CompletionContext<RES, T, RC> completionContext)
onStart(Request<RC> request)接受一个Request对象作为参数。它包含用于选择适当实例的数据,包括下游客户端请求和提示。onStartRequest也将Request对象和对象Response<T>作为参数。另一方面,CompletionContext向该方法提供一个对象onComplete(CompletionContext<RES, T, RC> completionContext)。它包含 LoadBalancer Response,包括所选的服务实例、Status针对该服务实例执行的请求的 和(如果可用)返回到下游客户端的响应,以及(如果发生异常)相应的Throwable.
该supports(Class requestContextClass, Class responseClass,
Class serverTypeClass)方法可用于确定所讨论的处理器是否处理所提供类型的对象。如果用户未覆盖,则返回true。
在前面的方法调用中,RC表示RequestContext类型,RES表示客户端响应类型,T表示返回的服务器类型。
|
3.16。Spring Cloud LoadBalancer 统计
我们提供了一个LoadBalancerLifecycle名为 的 bean MicrometerStatsLoadBalancerLifecycle,它使用 Micrometer 来提供负载平衡调用的统计信息。
为了将此 bean 添加到您的应用程序上下文中,请将 的值设置为spring.cloud.loadbalancer.stats.micrometer.enabled并true使其MeterRegistry可用(例如,通过将Spring Boot Actuator添加到您的项目中)。
MicrometerStatsLoadBalancerLifecycle在 中注册以下计量表MeterRegistry:
-
loadbalancer.requests.active:一个仪表,允许您监视任何服务实例当前活动请求的数量(通过标签提供的服务实例数据); -
loadbalancer.requests.success:一个计时器,用于测量已结束将响应传递给底层客户端的任何负载平衡请求的执行时间; -
loadbalancer.requests.failed:一个计时器,用于测量任何以异常结束的负载平衡请求的执行时间; -
loadbalancer.requests.discard:一个计数器,用于测量丢弃的负载平衡请求的数量,即 LoadBalancer 尚未检索到运行请求的服务实例的请求。
有关服务实例、请求数据和响应数据的附加信息将在可用时通过标签添加到指标中。
对于某些实现,例如BlockingLoadBalancerClient,请求和响应数据可能不可用,因为我们从参数建立通用类型,并且可能无法确定类型并读取数据。
|
| 当为给定仪表添加至少一条记录时,仪表就会在注册表中注册。 |
您可以通过添加来
进一步配置这些指标的行为(例如,添加发布百分位数和直方图)。
MeterFilters |
3.17。配置单独的 LoadBalancerClient
各个负载均衡器客户端可以使用不同的前缀单独配置,其中是负载均衡器的名称。默认配置值可以在命名空间中设置,并将优先与客户端特定值合并spring.cloud.loadbalancer.clients.<clientId>.clientIdspring.cloud.loadbalancer.
spring:
cloud:
loadbalancer:
health-check:
initial-delay: 1s
clients:
myclient:
health-check:
interval: 30s
上面的示例将生成一个带有和的合并运行状况检查@ConfigurationProperties对象。initial-delay=1sinterval=30s
除以下全局属性外,每个客户端配置属性适用于大多数属性:
-
spring.cloud.loadbalancer.enabled- 全局启用或禁用负载平衡 -
spring.cloud.loadbalancer.retry.enabled- 全局启用或禁用负载平衡重试。如果全局启用它,您仍然可以使用client-prefixed 属性禁用特定客户端的重试,但反之则不然 -
spring.cloud.loadbalancer.cache.enabled- 全局启用或禁用 LoadBalancer 缓存。如果全局启用它,您仍然可以通过创建不包含在委托层次结构中的自定义配置来禁用特定客户端的缓存,但反之则不然。CachingServiceInstanceListSupplierServiceInstanceListSupplier -
spring.cloud.loadbalancer.stats.micrometer.enabled- 全局启用或禁用 LoadBalancer Micrometer 指标
对于已使用映射的属性,您可以在不使用关键字的情况下为每个客户端指定不同的值clients(例如,hints, health-check.path),我们保留了该行为,以便保持库向后兼容。它将在下一个主要版本中进行修改。
|
首先4.0.4,我们在 中引入了该callGetWithRequestOnDelegates标志LoadBalancerProperties。如果此标志设置为true,ServiceInstanceListSupplier#get(Request request)则将实现方法来调用delegate.get(request)可分配的类DelegatingServiceInstanceListSupplier(尚未实现该方法),但不包括CachingServiceInstanceListSupplier和HealthCheckServiceInstanceListSupplier,应在供应商对实例执行实例检索后直接将其放置在实例供应商层次结构中。网络,在完成任何基于请求的过滤之前。然而,该标志默认4.0.x设置为,因为它将默认设置为。
false4.1.0true |
3.18。AOT 和本机映像支持
自 以来4.0.0,Spring Cloud LoadBalancer 支持 Spring AOT 转换和本机映像。但是,要使用此功能,您需要显式定义您的LoadBalancerClient服务 ID。您可以通过使用注释的value或属性或作为属性的值来执行此操作。name@LoadBalancerClientspring.cloud.loadbalancer.eager-load.clients
4. Spring Cloud 断路器
4.1. 介绍
Spring Cloud Circuit Breaker 提供了跨不同断路器实现的抽象。它提供了在您的应用程序中使用的一致 API,让您(开发人员)可以选择最适合您的应用程序需求的断路器实现。
4.2. 核心概念
要在代码中创建断路器,您可以使用CircuitBreakerFactoryAPI。当您在类路径中包含 Spring Cloud Circuit Breaker 启动器时,会自动为您创建一个实现此 API 的 bean。以下示例显示了如何使用此 API 的简单示例:
@Service
public static class DemoControllerService {
private RestTemplate rest;
private CircuitBreakerFactory cbFactory;
public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
this.rest = rest;
this.cbFactory = cbFactory;
}
public String slow() {
return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
}
}
该CircuitBreakerFactory.createAPI 创建一个名为 的类的实例CircuitBreaker。该run方法需要 aSupplier和 a Function。这Supplier是您要包装在断路器中的代码。这Function是断路器跳闸时运行的后备措施。该函数被传递Throwable导致触发回退。如果您不想提供后备方案,则可以选择排除后备方案。
4.2.1. 反应式代码中的断路器
如果 Project Reactor 位于类路径上,您也可以用于ReactiveCircuitBreakerFactory反应式代码。以下示例展示了如何执行此操作:
@Service
public static class DemoControllerService {
private ReactiveCircuitBreakerFactory cbFactory;
private WebClient webClient;
public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
this.webClient = webClient;
this.cbFactory = cbFactory;
}
public Mono<String> slow() {
return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
}
}
该ReactiveCircuitBreakerFactory.createAPI 创建一个名为 的类的实例ReactiveCircuitBreaker。该run方法采用 aMono或 aFlux并将其包装在断路器中。您可以选择分析一个后备Function,如果断路器跳闸并通过Throwable
导致故障的原因,将调用该后备。
4.3. 配置
您可以通过创建 类型的 bean 来配置断路器Customizer。该Customizer接口有一个方法(称为customize),可以进行Object自定义。
有关如何自定义给定实现的详细信息,请参阅以下文档:
有些CircuitBreaker实现比如每次调用Resilience4JCircuitBreakercall方法。它可能效率低下。在这种情况下,你可以使用方法。当多次调用没有意义时(例如,在使用 Resilience4j 的 events 的情况下),它非常有用。customizeCircuitBreaker#runCircuitBreaker#oncecustomize
io.github.resilience4j.circuitbreaker.CircuitBreaker下面的例子展示了各自消费事件的方式。
Customizer.once(circuitBreaker -> {
circuitBreaker.getEventPublisher()
.onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)
5. CachedRandomPropertySource
Spring Cloud Context 提供了PropertySource基于键缓存随机值的方法。除了缓存功能之外,它的工作原理与 Spring Boot 的RandomValuePropertySource. 如果您想要一个即使在 Spring 应用程序上下文重新启动后也保持一致的随机值,则此随机值可能很有用。属性值采用以下形式:键在缓存中的cachedrandom.[yourkey].[type]位置。yourkey该type值可以是 Spring Boot 的RandomValuePropertySource.
myrandom=${cachedrandom.appname.value}
6. 安全
6.1. 单点登录
| 在 1.3 版本中,所有 OAuth2 SSO 和资源服务器功能都转移到了 Spring Boot。您可以在Spring Boot 用户指南中找到文档 。 |
6.1.1. 客户端令牌中继
如果您的应用程序是面向 OAuth2 客户端的用户(即已声明
@EnableOAuth2Sso或@EnableOAuth2Client),那么它具有
OAuth2ClientContext来自 Spring Boot 的请求范围。OAuth2RestTemplate您可以从此上下文和 autowired创建自己的OAuth2ProtectedResourceDetails上下文,然后上下文将始终将访问令牌转发到下游,并且如果访问令牌过期,也会自动刷新访问令牌。(这些是 Spring Security 和 Spring Boot 的功能。)
6.1.2. 资源服务器令牌中继
如果您的应用程序有,@EnableResourceServer您可能希望将传入的令牌下游中继到其他服务。如果您使用 a
RestTemplate来联系下游服务,那么这只是如何使用正确的上下文创建模板的问题。
如果您的服务用于UserInfoTokenServices验证传入令牌(即它正在使用security.oauth2.user-info-uri
配置),那么您可以简单地OAuth2RestTemplate
使用自动装配创建一个OAuth2ClientContext(它将由验证过程在到达后端代码之前填充)。同样地(使用 Spring Boot 1.4),您可以注入 a
UserInfoRestTemplateFactory并OAuth2RestTemplate在配置中获取它。例如:
@Bean
public OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
return factory.getUserInfoRestTemplate();
}
OAuth2ClientContext
然后,此其余模板将具有与身份验证过滤器使用的相同(请求范围),因此您可以使用它来发送具有相同访问令牌的请求。
如果您的应用程序未使用UserInfoTokenServices但仍然是客户端(即它声明@EnableOAuth2Client或@EnableOAuth2Sso),则使用 Spring Security CloudOAuth2RestOperations用户从 an 创建的任何内容@Autowired OAuth2Context也将转发令牌。该功能默认作为 MVC 处理程序拦截器实现,因此仅适用于 Spring MVC。如果您不使用 MVC,您可以使用自定义过滤器或 AOP 拦截器包装
AccessTokenContextRelay来提供相同的功能。
下面是一个基本示例,显示了在其他地方创建的自动装配其余模板的使用(“foo.com”是一个资源服务器,接受与周围应用程序相同的令牌):
@Autowired
private OAuth2RestOperations restTemplate;
@RequestMapping("/relay")
public String relay() {
ResponseEntity<String> response =
restTemplate.getForEntity("https://foo.com/bar", String.class);
return "Success! (" + response.getBody() + ")";
}
如果您不想转发令牌(这是一个有效的选择,因为您可能想充当自己,而不是向您发送令牌的客户端),那么您只需要创建自己的令牌,而不是自动装配默认
OAuth2Context令牌一。
Feign 客户端还会选择一个使用 的拦截器(
OAuth2ClientContext如果可用),因此他们还应该在任何地方进行令牌中继RestTemplate。