loadbalancer源码分析

loadbalancer是如何实现挂载的

  • 我们可以通过源码追踪看他底层是如何实现的在pom文件中发现我们导入的依赖是
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
  • 去依赖里看他导进来的依赖,可以看到这里只有一个pom文件 点开pom文件发现里面导入了一个 spring-cloud-loadbalancer 的依赖

image-20231124225645413

  • 再去他的里面找源码

image-20231124225955852

  • 我们可以发现在spring.factories中找到他的配置类

image-20231124230335383

  • 通过翻译不难发现LoadBalancerAutoConfiguration是 负载均衡自动配置 按住ctrl+鼠标左键可以追踪
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.loadbalancer.config;

import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration;
import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerClientAutoConfiguration;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration(
proxyBeanMethods = false
)
@LoadBalancerClients //v表明所有的负载均衡都用这套方案
//EnableConfigurationProperties 配置项
@EnableConfigurationProperties({LoadBalancerClientsProperties.class})
//AutoConfigureBefore 表明要实现自动配置需要这两个字节码文件
@AutoConfigureBefore({ReactorLoadBalancerClientAutoConfiguration.class, LoadBalancerBeanPostProcessorAutoConfiguration.class})
@ConditionalOnProperty(
value = {"spring.cloud.loadbalancer.enabled"},
havingValue = "true",
matchIfMissing = true
)
public class LoadBalancerAutoConfiguration {
private final ObjectProvider<List<LoadBalancerClientSpecification>> configurations;
public LoadBalancerAutoConfiguration(ObjectProvider<List<LoadBalancerClientSpecification>> configurations) {
this.configurations = configurations;
}

@Bean
@ConditionalOnMissingBean
public LoadBalancerZoneConfig zoneConfig(Environment environment) {
return new LoadBalancerZoneConfig(environment.getProperty("spring.cloud.loadbalancer.zone"));
}

@ConditionalOnMissingBean
@Bean
public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties) {
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);
clientFactory.setConfigurations((List)this.configurations.getIfAvailable(Collections::emptyList));
return clientFactory;
}
}
  1. @LoadBalancerClients //v表明所有的客户端都用这套方案
  2. EnableConfigurationProperties 客户端的配置属性
  3. AutoConfigureBefore 表明要实现自动配置需要这两个字节码文件
  4. starter自动配置最重要的是其中最核心的其实是@Bean
  5. ​ @ConditionalOnMissingBean表示如果没有这个bean就新创建
  6. LoadBalancerZoneConfig 主要是做机架管理的不同的机房分成不同域,不用管
  7. LoadBalancerClientFactory的托管,是我们需要的,继续追踪
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.loadbalancer.support;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import org.springframework.cloud.context.named.NamedContextFactory;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.core.env.Environment;

public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification> implements ReactiveLoadBalancer.Factory<ServiceInstance> {
private static final Log log = LogFactory.getLog(LoadBalancerClientFactory.class);
public static final String NAMESPACE = "loadbalancer";
public static final String PROPERTY_NAME = "loadbalancer.client.name";
private final LoadBalancerClientsProperties properties;

/** @deprecated */
@Deprecated
public LoadBalancerClientFactory() {
this((LoadBalancerClientsProperties)null);
}

public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {
super(LoadBalancerClientConfiguration.class, "loadbalancer", "loadbalancer.client.name");
this.properties = properties;
}

public static String getName(Environment environment) {
return environment.getProperty("loadbalancer.client.name");
}

public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
return (ReactiveLoadBalancer)this.getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
}

public LoadBalancerProperties getProperties(String serviceId) {
if (this.properties == null) {
if (log.isWarnEnabled()) {
log.warn("LoadBalancerClientsProperties is null. Please use the new constructor.");
}

return null;
} else {
return (LoadBalancerProperties)(serviceId != null && this.properties.getClients().containsKey(serviceId) ? (LoadBalancerProperties)this.properties.getClients().get(serviceId) : this.properties);
}
}
}
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
return (ReactiveLoadBalancer)this.getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
}
  • 工厂方法中最重要的是获取实例对象,找到LoadBalancerClientFactory对应的getInstance()方法 在方法内部可以发现,它获取了ReactorServiceInstanceLoadBalancer.class (基于响应式的服务实列的负载均衡器)实例对象,继续追踪
  • serviceId其实是你注册的名称
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.loadbalancer.core;

import org.springframework.cloud.client.ServiceInstance;

public interface ReactorServiceInstanceLoadBalancer extends ReactorLoadBalancer<ServiceInstance> {
}
  • 点进去对象发现是一个接口(官方注释写:容许你选择一个服务注册的实列)那么我们就要去找他的实现类,其实loadbalance默认是轮询方式进行负载均衡,这个后面会说 ,这里是通过注册一个项目的两个服务 测试结果发现他会轮流调用

image-20231124232617203

  • 两个默认类一个是轮询一个是随机所以我们点进RoundRobinLoadBalancer里
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.loadbalancer.core;

import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import reactor.core.publisher.Mono;

public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Log log = LogFactory.getLog(RoundRobinLoadBalancer.class);
final AtomicInteger position;
final String serviceId;
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

public RoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
this(serviceInstanceListSupplierProvider, serviceId, (new Random()).nextInt(1000));
}

public RoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {
this.serviceId = serviceId;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.position = new AtomicInteger(seedPosition);
}

public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next().map((serviceInstances) -> {
return this.processInstanceResponse(supplier, serviceInstances);
});
}

private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
}

return serviceInstanceResponse;
}

private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + this.serviceId);
}

return new EmptyResponse();
} else if (instances.size() == 1) {
return new DefaultResponse((ServiceInstance)instances.get(0));
} else {
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
return new DefaultResponse(instance);
}
}
}
  • serviceInstanceListSupplierProvider-服务实例列表供应商提供商
//getIfAvailable()方法判断服务是否可用,如果可用获取服务实列NoopServiceInstanceListSupplier
ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
  • this.getInstanceResponse(serviceInstances); 获取相应实列

  • getInstanceResponse()方法是关键的使用那种负载均衡算法

//如果只有一个服务就返回这个
else if (instances.size() == 1) {
return new DefaultResponse((ServiceInstance)instances.get(0));
}
//假设我们现在有两个服务实列 请求第一次进来时 position为1,对整形最大值作模运算为本身,对服务实列个数取余为1 返回第二个服务,再发送请求,incrementAndGet方法会自增1,此时position为2,做相同操作 结果为0 返回第一个服务
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE; //与整形最大数作模运算
ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
  • 这样就通过长轮询实现了负载均衡

两种负载均衡方案loadbalancer默认使用哪个

我们可以通过注解追踪

@LoadBalancerClient

发现里面有一个

Class<?>[] configuration() default {};

下载注解后官方注释给出:

- A custom @Configuration for the load balancer client. Can contain override @Bean definition for the pieces that make up the client.
- Returns:
- configuration classes for the load balancer client.
- See Also:
- for the defaults
- 翻译这句话
- 负载平衡器客户端的自定义@Configuration。可以包含构成客户端的部分的覆盖@Bean定义。返回:负载平衡器客户端的配置类。另请参见: 对于默认值

点击for the defaults

@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RoundRobinLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}

默认返回了轮询负载均衡策略