Spring Cloud LoadBalancer

Spring Cloud 提供自己的客户端负载均衡器抽象和实现。对于负载均衡机制,已添加 ReactiveLoadBalancer 接口,并为它提供了 Round-Robin-basedRandom 实现。为了从响应式 ServiceInstanceListSupplier`中获取要选择的实例,我们已使用它。当前,我们支持 `ServiceInstanceListSupplier 的基于服务发现的实现,它使用类路径中可用的 Discovery Client 从服务发现中检索可用实例。

Spring Cloud provides its own client-side load-balancer abstraction and implementation. For the load-balancing mechanism, ReactiveLoadBalancer interface has been added and a Round-Robin-based and Random implementations have been provided for it. In order to get instances to select from reactive ServiceInstanceListSupplier is used. Currently we support a service-discovery-based implementation of ServiceInstanceListSupplier that retrieves available instances from Service Discovery using a Discovery Client available in the classpath.

可以通过将 spring.cloud.loadbalancer.enabled 的值设置为 false 来禁用 Spring Cloud LoadBalancer。

It is possible to disable Spring Cloud LoadBalancer by setting the value of spring.cloud.loadbalancer.enabled to false.

Eager loading of LoadBalancer contexts

Spring Cloud LoadBalancer 为每个服务 ID 创建一个单独的 Spring 子上下文。默认情况下,这些上下文在首次对服务 ID 进行负载均衡时会被延迟初始化。

Spring Cloud LoadBalancer creates a separate Spring child context for each service id. By default, these contexts are initialised lazily, whenever the first request for a service id is being load-balanced.

你可以选择立即加载这些上下文。为了做到这一点,请使用 spring.cloud.loadbalancer.eager-load.clients 属性指定你想要为其进行立即加载的服务 ID,例如:

You can choose to load those contexts eagerly. In order to do that, specify the service ids for which you want to do eager load using the spring.cloud.loadbalancer.eager-load.clients property, for example:

spring.cloud-loadbalancer.eager-load.clients[0]=my-first-client
spring.cloud-loadbalancer.eager-load.clients[1]=my-second-client

Switching between the load-balancing algorithms

默认使用的 ReactiveLoadBalancer 实现是 RoundRobinLoadBalancer。要在选定的服务或所有服务中切换到不同的实现,可以使用 custom LoadBalancer configurations mechanism

The ReactiveLoadBalancer implementation that is used by default is RoundRobinLoadBalancer. To switch to a different implementation, either for selected services or all of them, you can use the custom LoadBalancer configurations mechanism.

例如,可以通过 @LoadBalancerClient 注释传递以下配置,以切换到使用 RandomLoadBalancer

For example, the following configuration can be passed via @LoadBalancerClient annotation to switch to using the 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 进行注释,或者应处于组件扫描范围之外。

The classes you pass as @LoadBalancerClient or @LoadBalancerClients configuration arguments should either not be annotated with @Configuration or be outside component scan scope.

Spring Cloud LoadBalancer integrations

为了便于使用 Spring Cloud LoadBalancer,我们提供了 ReactorLoadBalancerExchangeFilterFunction(可与 WebClient 搭配使用)和 BlockingLoadBalancerClient(可与 RestTemplateRestClient 搭配使用)。你可以在以下部分中看到更多信息和使用示例:

To make it easy to use Spring Cloud LoadBalancer, we provide ReactorLoadBalancerExchangeFilterFunction (which can be used with WebClient) and BlockingLoadBalancerClient (which works with RestTemplate and RestClient). You can see more information and examples of usage in the following sections:

Spring Cloud LoadBalancer Caching

除了每次必须选择一个实例时都会通过 DiscoveryClient 检索实例的基本 ServiceInstanceListSupplier 实现之外,我们还提供了两种缓存实现。

Apart from the basic ServiceInstanceListSupplier implementation that retrieves instances via DiscoveryClient each time it has to choose an instance, we provide two caching implementations.

[[ caffeine-backed-loadbalancer-cache-implementation]]=== Caffeine支持的负载均衡器缓存实现

[[caffeine-backed-loadbalancer-cache-implementation]] === Caffeine-backed LoadBalancer Cache Implementation

如果类路径中存在 com.github.ben-manes.caffeine:caffeine,则将使用基于 Caffeine 的实现。有关如何配置它的信息,请参见 LoadBalancerCacheConfiguration部分。

If you have com.github.ben-manes.caffeine:caffeine in the classpath, Caffeine-based implementation will be used. See the LoadBalancerCacheConfiguration section for information on how to configure it.

如果您使用的是 Caffeine,还可以通过在 `spring.cloud.loadbalancer.cache.caffeine.spec`属性中传递自己的 Caffeine Specification来覆盖负载均衡器的默认 Caffeine 缓存设置。

If you are using Caffeine, you can also override the default Caffeine Cache setup for the LoadBalancer by passing your own Caffeine Specification in the spring.cloud.loadbalancer.cache.caffeine.spec property.

警告:传递你自己的 Caffeine 规范将覆盖所有其他 LoadBalancerCache 设置,包括 ttlcapacityGeneral LoadBalancer Cache Configuration 字段。

WARN: Passing your own Caffeine specification will override any other LoadBalancerCache settings, including General LoadBalancer Cache Configuration fields, such as ttl and capacity.

Default LoadBalancer Cache Implementation

如果类路径中没有 Caffeine,则将使用自动与 spring-cloud-starter-loadbalancer 一起提供的 DefaultLoadBalancerCache。有关如何配置它的信息,请参见 LoadBalancerCacheConfiguration 部分。

If you do not have Caffeine in the classpath, the DefaultLoadBalancerCache, which comes automatically with spring-cloud-starter-loadbalancer, will be used. See the LoadBalancerCacheConfiguration section for information on how to configure it.

要使用 Caffeine 而不是默认缓存,请将 com.github.ben-manes.caffeine:caffeine 从属项添加到类路径中。

To use Caffeine instead of the default cache, add the com.github.ben-manes.caffeine:caffeine dependency to classpath.

LoadBalancer Cache Configuration

你可以通过将 Spring Boot StringDuration 转换器语法 compliant with the link:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-conversion-duration[的 String 作为 spring.cloud.loadbalancer.cache.ttl 属性的值传递,设置自己的 ttl 值(写入后应使条目过期的时长),表示为 Duration。你还可以通过设置 spring.cloud.loadbalancer.cache.capacity 属性的值来设置自己的 LoadBalancer 缓存初始容量。

You can set your own ttl value (the time after write after which entries should be expired), expressed as Duration, by passing a String compliant with the Spring Boot String to Duration converter syntax. as the value of the spring.cloud.loadbalancer.cache.ttl property. You can also set your own LoadBalancer cache initial capacity by setting the value of the spring.cloud.loadbalancer.cache.capacity property.

默认设置包括将 ttl 设为 35 秒,而默认 initialCapacity256

The default setup includes ttl set to 35 seconds and the default initialCapacity is 256.

你也可以通过将 spring.cloud.loadbalancer.cache.enabled 的值设为 false 来彻底禁用负载均衡器缓存。

You can also altogether disable loadBalancer caching by setting the value of spring.cloud.loadbalancer.cache.enabled to false.

尽管基本的不带缓存的实现对于原型设计和测试非常有用,但它的效率远低于缓存版本,因此我们建议在生产环境中始终使用缓存版本。如果 DiscoveryClient 实现(例如 EurekaDiscoveryClient)已经完成了缓存,则应禁用负载均衡器缓存,以防止双重缓存。

Although the basic, non-cached, implementation is useful for prototyping and testing, it’s much less efficient than the cached versions, so we recommend always using the cached version in production. If the caching is already done by the DiscoveryClient implementation, for example EurekaDiscoveryClient, the load-balancer caching should be disabled to prevent double caching.

当你创建自己的配置时,如果你使用了 CachingServiceInstanceListSupplier,请确保将它放在直接位于通过网络检索实例的供应商之后的位置,例如 DiscoveryClientServiceInstanceListSupplier,在所有其他过滤供应商之前。

When you create your own configuration, if you use CachingServiceInstanceListSupplier make sure to place it in the hierarchy directly after the supplier that retrieves the instances over the network, for example, DiscoveryClientServiceInstanceListSupplier, before any other filtering suppliers.

Weighted Load-Balancing

为了启用加权负载均衡,我们提供了 WeightedServiceInstanceListSupplier。我们使用 WeightFunction 来计算每个实例的权重。默认情况下,我们尝试从元数据映射(密钥为 weight)中读取和解析权重。

To enable weighted load-balancing, we provide the WeightedServiceInstanceListSupplier. We use WeightFunction to calculate the weight of each instance. By default, we try to read and parse the weight from the metadata map (the key is weight).

如果元数据映射中未指定权重,则默认此实例的权重为 1。

If the weight is not specified in the metadata map, we default the weight of this instance to be 1.

你可以通过将 spring.cloud.loadbalancer.configurations 的值设为 weighted 或提供你自己的 ServiceInstanceListSupplier Bean 来配置它,例如:

You can configure it either by setting the value of spring.cloud.loadbalancer.configurations to weighted or by providing your own ServiceInstanceListSupplier bean, for example:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
					.withWeighted()
					.withCaching()
					.build(context);
	}
}

你还可以通过提供 WeightFunction 来自定义权重计算逻辑。

You can also customize the weight calculation logic by providing WeightFunction.

你可以使用此样本配置让所有实例具有随机权重:

You can use this sample configuration to make all instances have a random weight:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
					.withWeighted(instance -> ThreadLocalRandom.current().nextInt(1, 101))
					.withCaching()
					.build(context);
	}
}

Zone-Based Load-Balancing

为了启用基于区域的负载均衡,我们提供了 ZonePreferenceServiceInstanceListSupplier。我们使用`DiscoveryClient` 特定的 zone 配置(例如,eureka.instance.metadata-map.zone)来选择客户端为其尝试筛选可用服务实例的区域。

To enable zone-based load-balancing, we provide the ZonePreferenceServiceInstanceListSupplier. We use DiscoveryClient-specific zone configuration (for example, eureka.instance.metadata-map.zone) to pick the zone that the client tries to filter available service instances for.

你还可以通过设置 spring.cloud.loadbalancer.zone 属性的值来覆盖 DiscoveryClient 特定的区域设置。

You can also override DiscoveryClient-specific zone setup by setting the value of spring.cloud.loadbalancer.zone property.

目前,只有 Eureka Discovery Client 会被配置为设置 LoadBalancer 区域。对于其他发现客户端,设置 spring.cloud.loadbalancer.zone 属性。其他设备将很快推出。

For the time being, only Eureka Discovery Client is instrumented to set the LoadBalancer zone. For other discovery client, set the spring.cloud.loadbalancer.zone property. More instrumentations coming shortly.

要确定一个已检索的 ServiceInstance 的区域,我们会在其元数据映射中的 "zone" 键下检查该值。

To determine the zone of a retrieved ServiceInstance, we check the value under the "zone" key in its metadata map.

ZonePreferenceServiceInstanceListSupplier 筛选检索的实例,并仅返回同一区域中的实例。如果 zonenull 或者同一区域中没有实例,它将返回所有检索的实例。

The ZonePreferenceServiceInstanceListSupplier filters retrieved instances and only returns the ones within the same zone. If the zone is null or there are no instances within the same zone, it returns all the retrieved instances.

为了使用基于区域的负载均衡方法,你必须在 custom configuration 中实例化 ZonePreferenceServiceInstanceListSupplier Bean。

In order to use the zone-based load-balancing approach, you will have to instantiate a ZonePreferenceServiceInstanceListSupplier bean in a custom configuration.

我们使用委托与 ServiceInstanceListSupplier Bean 一起工作。我们建议使用 DiscoveryClientServiceInstanceListSupplier 委托,使用 CachingServiceInstanceListSupplier 包装它以利用 LoadBalancer caching mechanism,然后在 ZonePreferenceServiceInstanceListSupplier 的构造函数中传递生成的 Bean。

We use delegates to work with ServiceInstanceListSupplier beans. We suggest using a DiscoveryClientServiceInstanceListSupplier delegate, wrapping it with a CachingServiceInstanceListSupplier to leverage LoadBalancer caching mechanism, and then passing the resulting bean in the constructor of ZonePreferenceServiceInstanceListSupplier.

你可以使用此样本配置对其进行设置:

You can use this sample configuration to set it up:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
                    .withCaching()
					.withZonePreference()
					.build(context);
	}
}

Instance Health-Check for LoadBalancer

可以启用 LoadBalancer 的计划性健康检查。为此,提供了 HealthCheckServiceInstanceListSupplier。它会定期验证由委托 ServiceInstanceListSupplier 提供的实例是否仍然可用,并仅返回可用的实例,除非不存在这些实例 - 那么它将返回所有检索的实例。

It is possible to enable a scheduled HealthCheck for the LoadBalancer. The HealthCheckServiceInstanceListSupplier is provided for that. It regularly verifies if the instances provided by a delegate ServiceInstanceListSupplier are still alive and only returns the healthy instances, unless there are none - then it returns all the retrieved instances.

使用 SimpleDiscoveryClient 时,这种机制特别有用。对于由实际服务注册表支持的客户端,没有必要使用,因为我们在查询外部服务发现后已经获得了健康实例。

This mechanism is particularly helpful while using the SimpleDiscoveryClient. For the clients backed by an actual Service Registry, it’s not necessary to use, as we already get healthy instances after querying the external ServiceDiscovery.

此供应商还建议用于每项服务只有一小部分实例的设置,以避免在失败的实例上重试调用。

This supplier is also recommended for setups with a small number of instances per service in order to avoid retrying calls on a failing instance.

如果使用任何由服务发现支持的供应商,通常不需要添加此运行状况检查机制,因为我们直接从服务注册表中检索实例的运行状况状态。

If using any of the Service Discovery-backed suppliers, adding this health-check mechanism is usually not necessary, as we retrieve the health state of the instances directly from the Service Registry.

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-check 设置为 false 来禁用额外的运行状况检查,因为每次实例刷新也会触发运行状况检查。

The HealthCheckServiceInstanceListSupplier relies on having updated instances provided by a delegate flux. In the rare cases when you want to use a delegate that does not refresh the instances, even though the list of instances may change (such as the DiscoveryClientServiceInstanceListSupplier provided by us), you can set spring.cloud.loadbalancer.health-check.refetch-instances to true to have the instance list refreshed by the HealthCheckServiceInstanceListSupplier. You can then also adjust the refretch intervals by modifying the value of spring.cloud.loadbalancer.health-check.refetch-instances-interval and opt to disable the additional healthcheck repetitions by setting spring.cloud.loadbalancer.health-check.repeat-health-check to false as every instances refetch will also trigger a healthcheck.

HealthCheckServiceInstanceListSupplier 使用加有 spring.cloud.loadbalancer.health-check 前缀的属性。您可以为计划程序设置 initialDelayinterval。您可以通过设置 spring.cloud.loadbalancer.health-check.path.default 属性的值来为健康检查 URL 设置默认路径。您还可以通过设置 spring.cloud.loadbalancer.health-check.path.[SERVICE_ID] 属性的值来为给定的服务设置特定值,用您的服务的正确 ID 替换 [SERVICE_ID]。如果未指定 [SERVICE_ID],则默认使用 /actuator/health。如果将 [SERVICE_ID] 设置为 null 或为空值,则不会执行健康检查。您还可以通过设置 spring.cloud.loadbalancer.health-check.port 的值来为健康检查请求设置自定义端口。如果没有设置,则端口是指所请求的服务可在服务实例中获得的端口。

HealthCheckServiceInstanceListSupplier uses properties prefixed with spring.cloud.loadbalancer.health-check. You can set the initialDelay and interval for the scheduler. You can set the default path for the healthcheck URL by setting the value of the spring.cloud.loadbalancer.health-check.path.default property. You can also set a specific value for any given service by setting the value of the spring.cloud.loadbalancer.health-check.path.[SERVICE_ID] property, substituting [SERVICE_ID] with the correct ID of your service. If the [SERVICE_ID] is not specified, /actuator/health is used by default. If the [SERVICE_ID] is set to null or empty as a value, then the health check will not be executed. You can also set a custom port for health-check requests by setting the value of spring.cloud.loadbalancer.health-check.port. If none is set, the port under which the requested service is available at the service instance.

如果您使用默认路径 (/actuator/health),务必将 spring-boot-starter-actuator 添加到合作者依赖项中(除非您计划自行添加此类端点)。

If you rely on the default path (/actuator/health), make sure you add spring-boot-starter-actuator to your collaborator’s dependencies, unless you are planning to add such an endpoint on your own.

默认情况下,healthCheckFlux 将对已检索到的每个存活 ServiceInstance 进行传播。您可以通过将 spring.cloud.loadbalancer.health-check.update-results-list 的值设置为 false 来修改此行为。如果此属性设置为 false,则整个存活实例序列将首先收集到一个列表中,然后再进行传播,从而确保数据流不会在属性中设置的运行状况检查间隔之间传播值。

By default, the healthCheckFlux will emit on each alive ServiceInstance that has been retrieved. You can modify this behaviour by setting the value of spring.cloud.loadbalancer.health-check.update-results-list to false. If this property is set to false, the entire alive instances sequence is first collected into a list and only then emitted, which ensures the flux does not emit values in between the health-check intervals set in properties.

为了使用运行状况检查时间表方法,你必须在 custom configuration 中实例化 HealthCheckServiceInstanceListSupplier Bean。

In order to use the health-check scheduler approach, you will have to instantiate a HealthCheckServiceInstanceListSupplier bean in a custom configuration.

我们使用委托来处理 ServiceInstanceListSupplier Bean。我们建议在 HealthCheckServiceInstanceListSupplier 的构造函数中传入一个 DiscoveryClientServiceInstanceListSupplier 委托。

We use delegates to work with ServiceInstanceListSupplier beans. We suggest passing a DiscoveryClientServiceInstanceListSupplier delegate in the constructor of HealthCheckServiceInstanceListSupplier.

你可以使用此样本配置对其进行设置:

You can use this sample configuration to set it up:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
					.withHealthChecks()
					.build(context);
	    }
	}

对于非反应堆栈,请使用 withBlockingHealthChecks() 创建此供应商。您还可以传递您自己的 WebClientRestTemplateRestClient 实例以用于检查。

For the non-reactive stack, create this supplier with the withBlockingHealthChecks(). You can also pass your own WebClient, RestTemplate or RestClient instance to be used for the checks.

HealthCheckServiceInstanceListSupplier 具有基于 Reactor Flux replay() 的自己的缓存机制。因此,如果使用它,您可能需要跳过使用 `CachingServiceInstanceListSupplier`包装此供应商。

HealthCheckServiceInstanceListSupplier has its own caching mechanism based on Reactor Flux replay(). Therefore, if it’s being used, you may want to skip wrapping that supplier with CachingServiceInstanceListSupplier.

创建您自己的配置时,HealthCheckServiceInstanceListSupplier,确保将其放置在层次结构中,紧接在通过网络检索实例的供应商之后,例如 DiscoveryClientServiceInstanceListSupplier,在其他任何筛选供应商之前。

When you create your own configuration, HealthCheckServiceInstanceListSupplier, make sure to place it in the hierarchy directly after the supplier that retrieves the instances over the network, for example, DiscoveryClientServiceInstanceListSupplier, before any other filtering suppliers.

Same instance preference for LoadBalancer

你可以以这样一种方式设置 LoadBalancer,即如果可用,它会倾向于选择之前已选择的实例。

You can set up the LoadBalancer in such a way that it prefers the instance that was previously selected, if that instance is available.

为此,你需要使用 SameInstancePreferenceServiceInstanceListSupplier。你可以通过将 spring.cloud.loadbalancer.configurations 的值设为 same-instance-preference 或提供你自己的 ServiceInstanceListSupplier Bean(例如)来配置它:

For that, you need to use SameInstancePreferenceServiceInstanceListSupplier. You can configure it either by setting the value of spring.cloud.loadbalancer.configurations to same-instance-preference or by providing your own ServiceInstanceListSupplier bean — for example:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
					.withSameInstancePreference()
					.build(context);
	    }
	}

这也是 Zookeeper StickyRule 的替代方法。

This is also a replacement for Zookeeper StickyRule.

Request-based Sticky Session for LoadBalancer

你可以以这样一种方式设置 LoadBalancer,即它会根据请求 Cookie 中提供的 instanceId 倾向于选择实例。如果请求通过 ClientRequestContext 或 ServerHttpRequestContext 传递给 LoadBalancer,我们目前支持这一点,这些 Context 由 SC LoadBalancer 交换过滤器函数和过滤器使用。

You can set up the LoadBalancer in such a way that it prefers the instance with instanceId provided in a request cookie. We currently support this if the request is being passed to the LoadBalancer through either ClientRequestContext or ServerHttpRequestContext, which are used by the SC LoadBalancer exchange filter functions and filters.

为此,你需要使用 RequestBasedStickySessionServiceInstanceListSupplier。你可以通过将 spring.cloud.loadbalancer.configurations 的值设为 request-based-sticky-session 或提供你自己的 ServiceInstanceListSupplier Bean(例如)来配置它:

For that, you need to use the RequestBasedStickySessionServiceInstanceListSupplier. You can configure it either by setting the value of spring.cloud.loadbalancer.configurations to request-based-sticky-session or by providing your own ServiceInstanceListSupplier bean — for example:

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

For that functionality, it is useful to have the selected service instance (which can be different from the one in the original request cookie if that one is not available) to be updated before sending the request forward. To do that, set the value of spring.cloud.loadbalancer.sticky-session.add-service-instance-cookie to true.

默认情况下,Cookie 的名称为 sc-lb-instance-id。您可以通过更改 spring.cloud.loadbalancer.instance-id-cookie-name 属性的值来修改它。

By default, the name of the cookie is sc-lb-instance-id. You can modify it by changing the value of the spring.cloud.loadbalancer.instance-id-cookie-name property.

当前,WebClient 支持此功能实现负载均衡。

This feature is currently supported for WebClient-backed load-balancing.

Spring Cloud LoadBalancer Hints

Spring Cloud LoadBalancer 让您可以设置在 Request 对象内传递到负载均衡器的 String 提示,此后这将在可以处理它们的 ReactiveLoadBalancer 实现中使用。

Spring Cloud LoadBalancer lets you set String hints that are passed to the LoadBalancer within the Request object and that can later be used in ReactiveLoadBalancer implementations that can handle them.

您可以通过设置 spring.cloud.loadbalancer.hint.default 属性的值来为所有服务设置一个默认提示。您还可通过设置 spring.cloud.loadbalancer.hint.[SERVICE_ID] 属性的值来为给定的服务设置特定值,用您的服务的正确 ID 替换 [SERVICE_ID]。如果用户未设置提示,则使用 default

You can set a default hint for all services by setting the value of the spring.cloud.loadbalancer.hint.default property. You can also set a specific value for any given service by setting the value of the spring.cloud.loadbalancer.hint.[SERVICE_ID] property, substituting [SERVICE_ID] with the correct ID of your service. If the hint is not set by the user, default is used.

Hint-Based Load-Balancing

我们还提供了一个 HintBasedServiceInstanceListSupplier,它是一个用于基于提示的实例选择的 ServiceInstanceListSupplier 实现。

We also provide a HintBasedServiceInstanceListSupplier, which is a ServiceInstanceListSupplier implementation for hint-based instance selection.

HintBasedServiceInstanceListSupplier 会检查提示请求头(默认头名称为 X-SC-LB-Hint,但您可以通过更改 spring.cloud.loadbalancer.hint-header-name 属性的值来修改它),并且如果它找到提示请求头,则会使用头中传递的提示值来过滤服务实例。

HintBasedServiceInstanceListSupplier checks for a hint request header (the default header-name is X-SC-LB-Hint, but you can modify it by changing the value of the spring.cloud.loadbalancer.hint-header-name property) and, if it finds a hint request header, uses the hint value passed in the header to filter service instances.

如果没有添加提示标头,则 HintBasedServiceInstanceListSupplier 使用 hint values from properties 过滤服务实例。

If no hint header has been added, HintBasedServiceInstanceListSupplier uses hint values from properties to filter service instances.

如果未设置提示(无论通过头还是属性),都将返回委托提供的全部服务实例。

If no hint is set, either by the header or by properties, all service instances provided by the delegate are returned.

在过滤过程中,HintBasedServiceInstanceListSupplier 会寻找在其 metadataMap 中的 hint 键下具有匹配值设置的服务实例。如果没有找到匹配的实例,则将返回委托提供的全部实例。

While filtering, HintBasedServiceInstanceListSupplier looks for service instances that have a matching value set under the hint key in their metadataMap. If no matching instances are found, all instances provided by the delegate are returned.

您可以使用以下示例配置来设置它:

You can use the following sample configuration to set it up:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
                    .withCaching()
					.withHints()
					.build(context);
	}
}

Transform the load-balanced HTTP request

您可以使用选定的 ServiceInstance 来转换负载均衡的 HTTP 请求。

You can use the selected ServiceInstance to transform the load-balanced HTTP Request.

对于 RestTemplateRestClient,您需要按如下方式实现并定义 LoadBalancerRequestTransformer

For RestTemplate and RestClient, you need to implement and define LoadBalancerRequestTransformer as follows:

@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

For WebClient, you need to implement and define LoadBalancerClientRequestTransformer as follows:

@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_ORDERLoadBalancerClientRequestTransformer.DEFAULT_ORDER 来指定顺序。

If multiple transformers are defined, they are applied in the order in which Beans are defined. Alternatively, you can use LoadBalancerRequestTransformer.DEFAULT_ORDER or LoadBalancerClientRequestTransformer.DEFAULT_ORDER to specify the order.

Spring Cloud LoadBalancer Subset

SubsetServiceInstanceListSupplier 实施了一个 deterministic subsetting algorithmServiceInstanceListSupplier 委托层次结构中选择数量有限的实例。

SubsetServiceInstanceListSupplier implements a deterministic subsetting algorithm to select a limited number of instances in the ServiceInstanceListSupplier delegates hierarchy.

您可以通过将 spring.cloud.loadbalancer.configurations 的值设置为 subset 或提供您自己的 ServiceInstanceListSupplier bean 来配置它,例如:

You can configure it either by setting the value of spring.cloud.loadbalancer.configurations to subset or by providing your own ServiceInstanceListSupplier bean — for example:

public class CustomLoadBalancerConfiguration {

	@Bean
	public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
			ConfigurableApplicationContext context) {
		return ServiceInstanceListSupplier.builder()
					.withDiscoveryClient()
					.withSubset()
					.withCaching()
					.build(context);
	    }
	}

默认情况下,每个服务实例都分配一个唯一的 instanceId,并且不同的 instanceId 值通常会选择不同的子集。通常,您无需关注它。但是,如果您需要让多个实例选择相同的子集,您可以使用 spring.cloud.loadbalancer.subset.instance-id 来设置它(它支持占位符)。

By default, each service instance is assigned a unique instanceId, and different instanceId values often select different subsets. Normally, you need not pay attention to it. However, if you need to have multiple instances select the same subset, you can set it with spring.cloud.loadbalancer.subset.instance-id (which supports placeholders).

默认情况下,子集大小设置为 100。您还可以使用 spring.cloud.loadbalancer.subset.size 设置它。

By default, the size of the subset is set to 100. You can also set it with spring.cloud.loadbalancer.subset.size.

Spring Cloud LoadBalancer Starter

我们还提供了一个 starter,让您轻松在 Spring Boot 应用程序中添加 Spring Cloud LoadBalancer。要使用它,只需在构建文件中将 org.springframework.cloud:spring-cloud-starter-loadbalancer 添加到您的 Spring Cloud 依赖项中。

We also provide a starter that allows you to easily add Spring Cloud LoadBalancer in a Spring Boot app. In order to use it, just add org.springframework.cloud:spring-cloud-starter-loadbalancer to your Spring Cloud dependencies in your build file.

Spring Cloud LoadBalancer starter 包括 Spring Boot CachingEvictor

Spring Cloud LoadBalancer starter includes Spring Boot Caching and Evictor.

Passing Your Own Spring Cloud LoadBalancer Configuration

您还可以使用 @LoadBalancerClient 注释来传递您自己的负载均衡器客户端配置,如下所述传递负载均衡器客户端的名称和配置类:

You can also use the @LoadBalancerClient annotation to pass your own load-balancer client configuration, passing the name of the load-balancer client and the configuration class, as follows:

@Configuration
@LoadBalancerClient(value = "stores", configuration = CustomLoadBalancerConfiguration.class)
public class MyConfiguration {

	@Bean
	@LoadBalanced
	public WebClient.Builder loadBalancedWebClientBuilder() {
		return WebClient.builder();
	}
}

为了让您更轻松地处理您自己的 LoadBalancer 配置,我们已向 ServiceInstanceListSupplier 类中添加了一个 builder() 方法。

In order to make working on your own LoadBalancer configuration easier, we have added a builder() method to the ServiceInstanceListSupplier class.

您还可以使用我们的其他预定义配置代替默认配置,通过将 spring.cloud.loadbalancer.configurations 属性的值设置为 zone-preference 来使用带有缓存的 ZonePreferenceServiceInstanceListSupplier,或设置为 health-check 来使用带有缓存的 HealthCheckServiceInstanceListSupplier

You can also use our alternative predefined configurations in place of the default ones by setting the value of spring.cloud.loadbalancer.configurations property to zone-preference to use ZonePreferenceServiceInstanceListSupplier with caching or to health-check to use HealthCheckServiceInstanceListSupplier with caching.

您可以使用此功能来实例化您自己编写或我们提供作为替代方案(例如 ZonePreferenceServiceInstanceListSupplier)的 ServiceInstanceListSupplierReactorLoadBalancer 的不同实现,以覆盖默认设置。

You can use this feature to instantiate different implementations of ServiceInstanceListSupplier or ReactorLoadBalancer, either written by you, or provided by us as alternatives (for example ZonePreferenceServiceInstanceListSupplier) to override the default setup.

你可以看到自定义配置 here 的示例。

You can see an example of a custom configuration here.

注释 value 参数(如上文中的 stores)指定我们应该使用给定的自定义配置向其发送请求的服务的服务 ID。

The annotation value arguments (stores in the example above) specifies the service id of the service that we should send the requests to with the given custom configuration.

您还可以通过 @LoadBalancerClients 注释传递多个配置(用于多个负载均衡器客户端),如下面的示例所示:

You can also pass multiple configurations (for more than one load-balancer client) through the @LoadBalancerClients annotation, as the following example shows:

@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 进行注释,或者应处于组件扫描范围之外。

The classes you pass as @LoadBalancerClient or @LoadBalancerClients configuration arguments should either not be annotated with @Configuration or be outside component scan scope.

创建您自己的配置时,如果您使用 CachingServiceInstanceListSupplierHealthCheckServiceInstanceListSupplier,请确保只使用其中一个,并且请确保将其放置在层次结构中,紧接在通过网络检索实例的供应商之后,例如 DiscoveryClientServiceInstanceListSupplier,在其他任何筛选供应商之前。

When you create your own configuration, if you use CachingServiceInstanceListSupplier or HealthCheckServiceInstanceListSupplier, makes sure to use one of them, not both, and make sure to place it in the hierarchy directly after the supplier that retrieves the instances over the network, for example, DiscoveryClientServiceInstanceListSupplier, before any other filtering suppliers.

Spring Cloud LoadBalancer Lifecycle

可能使用 Custom LoadBalancer configuration 注册的一类 Bean 是 LoadBalancerLifecycle

One type of bean that it may be useful to register using Custom LoadBalancer configuration is LoadBalancerLifecycle.

LoadBalancerLifecycle Bean 提供名为 onStart(Request<RC> request)onStartRequest(Request<RC> request, Response<T> lbResponse)onComplete(CompletionContext<RES, T, RC> completionContext) 的回调方法,您应实现这些方法来指定在负载均衡前后应执行哪些操作。

The LoadBalancerLifecycle beans provide callback methods, named onStart(Request<RC> request), onStartRequest(Request<RC> request, Response<T> lbResponse) and onComplete(CompletionContext<RES, T, RC> completionContext), that you should implement to specify what actions should take place before and after load-balancing.

onStart(Request<RC> request) 接收 Request 对象作为参数。它包含用于选择适当实例的数据,包括下游客户端请求和 hintonStartRequest 也接收 Request 对象,此外,还将 Response<T> 对象作为参数。另一方面,向 onComplete(CompletionContext<RES, T, RC> completionContext) 方法提供了 CompletionContext 对象。它包含负载均衡器 Response,包括所选的服务实例、对该服务实例执行的请求的 Status 以及(如果可用)返回给下游客户端的响应,以及(如果发生异常)相应的 Throwable

onStart(Request<RC> request) takes a Request object as a parameter. It contains data that is used to select an appropriate instance, including the downstream client request and hint. onStartRequest also takes the Request object and, additionally, the Response<T> object as parameters. On the other hand, a CompletionContext object is provided to the onComplete(CompletionContext<RES, T, RC> completionContext) method. It contains the LoadBalancer Response, including the selected service instance, the Status of the request executed against that service instance and (if available) the response returned to the downstream client, and (if an exception has occurred) the corresponding Throwable.

supports(Class requestContextClass, Class responseClass,Class serverTypeClass) 方法可用于确定有问题的处理器是否会处理所提供类型对象。如果没有被用户覆盖,它会返回 true

The supports(Class requestContextClass, Class responseClass, Class serverTypeClass) method can be used to determine whether the processor in question handles objects of provided types. If not overridden by the user, it returns true.

在前面的方法调用中,RC 表示 RequestContext 类型,RES 表示客户端响应类型,T 表示返回的服务器类型。

In the preceding method calls, RC means RequestContext type, RES means client response type, and T means returned server type.

Spring Cloud LoadBalancer Statistics

我们提供了一个名为 MicrometerStatsLoadBalancerLifecycleLoadBalancerLifecycle Bean,它使用 Micrometer 为负载均衡的调用提供统计数据。

We provide a LoadBalancerLifecycle bean called MicrometerStatsLoadBalancerLifecycle, which uses Micrometer to provide statistics for load-balanced calls.

要将此 bean 添加到应用程序上下文,请将 spring.cloud.loadbalancer.stats.micrometer.enabled 的值设置为 true,并提供一个 MeterRegistry(例如,通过将 Spring Boot Actuator 添加到您的项目)。

In order to get this bean added to your application context, set the value of the spring.cloud.loadbalancer.stats.micrometer.enabled to true and have a MeterRegistry available (for example, by adding Spring Boot Actuator to your project).

MicrometerStatsLoadBalancerLifecycleMeterRegistry 中注册以下指标:

MicrometerStatsLoadBalancerLifecycle registers the following meters in MeterRegistry:

  • loadbalancer.requests.active: A gauge that allows you to monitor the number of currently active requests for any service instance (service instance data available via tags);

  • loadbalancer.requests.success: A timer that measures the time of execution of any load-balanced requests that have ended in passing a response on to the underlying client;

  • loadbalancer.requests.failed: A timer that measures the time of execution of any load-balanced requests that have ended with an exception;

  • loadbalancer.requests.discard: A counter that measures the number of discarded load-balanced requests, i.e. requests where a service instance to run the request on has not been retrieved by the LoadBalancer.

每当存在时,都会通过标签向指标添加有关服务实例、请求数据和响应数据更多信息相关的信息。

Additional information regarding the service instances, request data, and response data is added to metrics via tags whenever available.

对于某些实现,例如 BlockingLoadBalancerClient,可能无法获得请求和响应数据,因为我们从参数中建立了泛型类型,并可能无法确定类型和读取数据。

For some implementations, such as BlockingLoadBalancerClient, request and response data might not be available, as we establish generic types from arguments and might not be able to determine the types and read the data.

当至少为给定测量仪添加一条记录时,会在注册表中注册测量仪。

The meters are registered in the registry when at least one record is added for a given meter.

您可以通过 adding MeterFilters进一步配置这些指标的行为(例如,添加 publishing percentiles and histograms)。

You can further configure the behavior of those metrics (for example, add publishing percentiles and histograms) by adding MeterFilters.

Configuring Individual LoadBalancerClients

可以通过不同的前缀 spring.cloud.loadbalancer.clients.<clientId>. 单独配置个别 Loadbalancer 客户端,其中 clientId 是负载均衡器的名称。可以在 spring.cloud.loadbalancer. 命名空间中设置默认配置值,并将其与特定于客户端的值合并,其中客户端值优先。

Individual Loadbalancer clients may be configured individually with a different prefix spring.cloud.loadbalancer.clients.<clientId>. where clientId is the name of the loadbalancer. Default configuration values may be set in the spring.cloud.loadbalancer. namespace and will be merged with the client specific values taking precedence

application.yml
spring:
  cloud:
    loadbalancer:
      health-check:
        initial-delay: 1s
      clients:
        myclient:
          health-check:
            interval: 30s

以上示例将得到一个合并的健康检查 @ConfigurationProperties 对象,其中 initial-delay=1sinterval=30s

The above example will result in a merged health-check @ConfigurationProperties object with initial-delay=1s and interval=30s.

每个客户端的配置属性适用于大部分属性,以下全局属性除外:

The per-client configuration properties work for most of the properties, apart from the following global ones:

  • spring.cloud.loadbalancer.enabled - globally enables or disables load-balancing

  • spring.cloud.loadbalancer.retry.enabled - globally enables or disables load-balanced retries. If you enable it globally, you can still disable retries for specific clients using the client-prefixed properties, but not the other way round

  • spring.cloud.loadbalancer.cache.enabled - globally enables or disables LoadBalancer caching. If you enable it globally, you can still disable caching for specific clients by creating a custom configuration that does not include the CachingServiceInstanceListSupplier in the ServiceInstanceListSupplier delegates hierarchy, but not the other way round.

  • spring.cloud.loadbalancer.stats.micrometer.enabled - globally enables or disables LoadBalancer Micrometer metrics

对于已使用地图的属性,在无需使用 clients 关键字(例如,hintshealth-check.path)的情况下每位客户端可以指定一个不同的值,已保持这种行为以便使库向后兼容。它将在下一个主要版本中进行修改。

For the properties where maps where already used, where you can specify a different value per-client without using the clients keyword (for example, hints, health-check.path), we have kept that behaviour in order to keep the library backwards compatible. It will be modified in the next major release.

4.1.0 开始,我们在 LoadBalancerProperties 中引入了 callGetWithRequestOnDelegates 标志。如果此标志设置为 trueServiceInstanceListSupplier#get(Request request) 方法将被实现以在 DelegatingServiceInstanceListSupplier 可赋值的类中调用 delegate.get(request),而这些类尚未实现此方法,不包括 CachingServiceInstanceListSupplierHealthCheckServiceInstanceListSupplier,将它们置于实例提供者层次结构中,紧接通过网络执行实例检索的提供者之后,在执行任何基于请求的筛选之前。默认设置为 true

Starting with 4.1.0, we have introduced the callGetWithRequestOnDelegates flag in LoadBalancerProperties. If this flag is set to true, ServiceInstanceListSupplier#get(Request request) method will be implemented to call delegate.get(request) in classes assignable from DelegatingServiceInstanceListSupplier that don’t already implement that method, with the exclusion of CachingServiceInstanceListSupplier and HealthCheckServiceInstanceListSupplier, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done. It is set to true by default.

[[-aot-and-native-image-support]]== AOT 和本机映像支持

[[-aot-and-native-image-support]] == AOT and Native Image Support

4.0.0 起,Spring Cloud LoadBalancer 支持 Spring AOT 转换和原生映像。但是,要使用此功能,您需要明确定义 LoadBalancerClient 服务 ID。您可以借助 @LoadBalancerClient 注释的 valuename 属性或使用 spring.cloud.loadbalancer.eager-load.clients 属性的值来执行此操作。

Since 4.0.0, Spring Cloud LoadBalancer supports Spring AOT transformations and native images. However, to use this feature, you need to explicitly define your LoadBalancerClient service IDs. You can do so by using the value or name attributes of the @LoadBalancerClient annotation or as values of the spring.cloud.loadbalancer.eager-load.clients property.