Ribbon负载均衡
什么是负载均衡?
- 负载均衡是一种算法,通过这种算法可以从服务地址列表中获取一个地址进行服务调用
- 在springcloud中提供了负载均衡器:Ribbon
Ribbon是Netflix提供的负载均衡器.为Ribbon提供服务提供者地址列表后,就可以根据某种负载均衡算法自动的帮助消费者去请求.Ribbon默认提供了很多负载均衡算法,如轮询,随机等.也可以自定义负载均衡算法
//在消费者启动类添加代码
@Bean
@LoadBalanced //使用负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
Ribbon简单原理
LoadBalancerClient.java是实现负载均衡的主要接口,
RestTemplate通过注解@LoadBalance开启了负载均衡器
SpringCloud的自动配置类LoadBalancerAutoConfiguration中传入了负载均衡拦截器LoadBalancerInterceptor.java
@Configuration(proxyBeanMethods = false)
@Conditional(RetryMissingOrDisabledCondition.class)
static class 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);
};
}
}
只要实现了注解@LoadBalance的RestTemplate发送http请求就会被LoadBalancerInterceptor类的intercept函数拦截,函数中调用了LoadBalancerClient的execute方法
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) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
//拦截RestTemplate发送的请求,并通过负载均衡算法得到一个可用的服务地址
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
//调用LoadBalancerClient的execute方法进行负载均衡算法
return this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
}
BlockingLoadBalancerClient实现了LoadBalancerClient接口,并重写了choose方法,
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
String hint = getHint(serviceId);
LoadBalancerRequestAdapter<T, DefaultRequestContext> lbRequest = new LoadBalancerRequestAdapter<>(request,
new DefaultRequestContext(request, hint));
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
.getSupportedLifecycleProcessors(
loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
DefaultRequestContext.class, Object.class, ServiceInstance.class);
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
//调用choose方法得到一个可用的服务地址信息
ServiceInstance serviceInstance = choose(serviceId, lbRequest);
if (serviceInstance == null) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(
new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, new EmptyResponse())));
throw new IllegalStateException("No instances available for " + serviceId);
}
//执行请求
return execute(serviceId, serviceInstance, lbRequest);
}
@Override
public <T> ServiceInstance choose(String serviceId, Request<T> request) {
ReactiveLoadBalancer<ServiceInstance> loadBalancer = loadBalancerClientFactory.getInstance(serviceId);
if (loadBalancer == null) {
return null;
}
//loadBalancer.choose(request)执行负载均衡算法,默认为轮询,计算出一个请求地址
Response<ServiceInstance> loadBalancerResponse = Mono.from(loadBalancer.choose(request)).block();
if (loadBalancerResponse == null) {
return null;
}
return loadBalancerResponse.getServer();
}