5SpringCloudLoadBalancer负载均衡架构解析

学习目标

  • 客户端负载均衡的设计方法和策略
  • Spring Cloud LoadBalancer的抽象和实现原理

负载均衡是一种基础设施类技术组件,往往和服务发现机制结合使用

目录

  • LoadBalancerClient
  • RestTemplate与负载均衡
  • Feign与负载均衡

LoadBalancerClient

LoadBalancerClient

LoadBalancerClient接口
BlockingLoadBalancerClient类的
choose获取负载均衡器实例,获取服务实例
execute执行请求

ReactiveLoadBalancer


RandomLoadBalancer 框架实现的随机负载均衡器
LoadBalancerClientFactory 获取负载均衡器LoadBalancerClient
LoadBalancerRequestFactory 封装并发起请求

RestTemplate与负载均衡

@LoadBalanced核心类

LoadBalanced注解

1
2
3
4
5
//自动具备负载均衡机制
@LoadBalancedaBean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
1
2
3
4
5
6
@Target({ ElementType,FIELD, ElementType,PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {}

LoadBalancerAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@confiquration(proxvBeanMethods = false)
@Conditional0nClass(RestTemplate.class)
@Conditional0nBean(LoadBalancerClient.class)@EnableConfigurationProperties(LoadBalancerClientsProperties.class)public class LoadBalancerAutoConfiguration {

@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestfactory loadBalancerRequestfactory(LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
}

LoadBalancerInterceptorConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration(
proxyBeanMethods = false
)
@Conditional({RetryMissingOrDisabledCondition.class})
static class LoadBalancerInterceptorConfig {
LoadBalancerInterceptorConfig() {
}

@Bean
public LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return (restTemplate) -> {
List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);//添加拦截
};
}
}

loadBalancerInterceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;

public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}

public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
}

BlockingLoadBalancerClientAutoconfiguration中注入loadBalancer

自定义负载均衡机制

  • 定义@MyLoadBalanced注解
  • 实现MyLoadBalancerAutoConfiguration配置类
  • 实现MyLoadBalancerInterceptor
  • 在RestTemplate上使用@MyLoadBalanced注解

为什么在RestTemplate添加@Loadbalanced注解就能实现负载均衡?
添加RestTemplate的拦截器,拦截器使用LoadBalancerClient实现负载均衡

Feign与负载均衡

1
2
3
4
5
6
7
8
@ConditionalOnClass(Feign.class)
@ConditionalOnBean({ LoadBalancerctient,class, LoadBalancerclientFactory.class })
@AutoConfigureBefore(FeignAutoConfiguration.class)@AutoConfigureAfter({BlockingLoadBalancerclientAutoConfiguration.class,LoadBalancerAutoconfiquration.class})@EnableConfigurationProperties(FeignHttpclientProperties.class)
@Configuration(proxyBeanMethods =false)
@Import({ HttpClientFeignLoadBalancerConfiguration.class,OkHttpFeignLoadBalancerConfiguration.class,HttpClient5FeignLoadBalancerConfiguration.class,DefaultFeignLoadBalancerConfiguration.class})
public class FeignLoadBalancerAutoConfiguration{
}

DefaultFeignLoadBalancerConfiguration

1
2
3
@Configuration(proxyBeanMethods =false)@EnableConfigurationProperties(LoadBalancerclientsProperties.class)class DefaultFeignLoadBalancerConfigurationf
aBeanaConditionalOnMissingBean@Conditional(0nRetryNotEnabledcondition.class)public client feignclient(LoadBalancerclient loadBalancerclientLoadBalancerClientFactory loadBalancerclientFactory){return new FeignBlockingLoadBalancerclient(new client,Default(null, null), loadBalancerclient,
loadBalancerClientFactory);

思考题

这几个注解的用法
@ConditionOnClass(RestTemplate.class)
@ConditionOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)

@AutoConfiqureAfter(LoadBalancerAutoConfiquration.class)
BlockingLoadBalancerClientAutoconfiguration

ClientHttpRequestInterceptor
Hint机制