1、版本参考
版本参照:
springboot:2.6.9
springcloud:2021.0.1
alibaba-nacos-discovery:2021.0.1.0
SpringCloud官方推荐使用spring-cloud-starter-loadbalancer进行负载均衡。
可解决在大集群下,微服务负载不均衡问题。
2、SpringCloud 负载均衡接口分析
接口:ReactorServiceInstanceLoadBalancer
自定义实现,就是去实现这个ReactorServiceInstanceLoadBalancer接口。
默认实现的随机负载、轮训负载可查看RandomLoadBalancer、RoundRobinLoadBalancer类
3.自定义实现LoadBalancer
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
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 org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
/**
*
* @author Admin-WPG
*
*/
public class UnitLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Log logger = LogFactory.getLog(UnitReactorServiceInstanceLoadBalancer.class);
private final String serviceId;
private final AtomicInteger position;
// 服务列表
private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
public UnitLoadBalancer(String serviceId,
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
this(serviceId, new Random().nextInt(1000), serviceInstanceListSupplierProvider);
}
public UnitLoadBalancer(String serviceId, int seed,
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
this.serviceId = serviceId;
this.position = new AtomicInteger(seed);
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
}
@SuppressWarnings("rawtypes")
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next()
.map(serviceInstances -> processInstanceResponse(request, supplier, serviceInstances));
}
private Response<ServiceInstance> processInstanceResponse(Request<?> request, ServiceInstanceListSupplier supplier,
List<ServiceInstance> serviceInstances) {
Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
}
return serviceInstanceResponse;
}
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("No servers available for service: " + serviceId);
}
return new EmptyResponse();
}
// 自定义
return this.getClusterRobinResponse(instances);
// 默认RoundRobinLoadBalancer
// return this.getRoundRobinInstance(instances);
// 随机
//return this.getRandomInstance(instances);
}
/**
* 使用随机算法 参考{link
* {@link org.springframework.cloud.loadbalancer.core.RandomLoadBalancer}}
*
* @param instances 实例
* @return {@link Response }<{@link ServiceInstance }>
*/
private Response<ServiceInstance> getRandomInstance(List<ServiceInstance> instances) {
int index = ThreadLocalRandom.current().nextInt(instances.size());
ServiceInstance instance = instances.get(index);
return new DefaultResponse(instance);
}
/**
* 使用RoundRobin机制获取节点
*
* @param instances 实例
* @return {@link Response }<{@link ServiceInstance }>
*/
private Response<ServiceInstance> getRoundRobinInstance(List<ServiceInstance> instances) {
// 每一次计数器都自动+1,实现轮询的效果
int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
ServiceInstance instance = instances.get(pos % instances.size());
return new DefaultResponse(instance);
}
/**
* 自定义的负载策略
*
* @param instances
* @return
*/
private Response<ServiceInstance> getClusterRobinResponse(List<ServiceInstance> instances) {
// 简单的轮训算法,在集群环境中,会出现不平衡的问题。
return getRoundRobinInstance(instances);
}
}
4. 创建配置类Configuration
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
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;
import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery;
import com.wpen.unit.LoadBalanceProperties;
import com.wpen.unit.lb.UnitLoadBalancer;
/**
*
* @author Admin-WPG
*
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter({ CachingServiceInstanceListSupplier.class, NacosServiceDiscovery.class })
@EnableConfigurationProperties(LoadBalanceProperties.class)
public class UnitLoadBalancerConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(LoadBalancerClientFactory.class)
public ReactorServiceInstanceLoadBalancer customLoadBalancer(LoadBalanceProperties loadBalanceProperties,
Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new UnitLoadBalancer(name,
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class));
}
}
5、加载配置 @LoadBalancerClients
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
/**
*
* @author Admin-WPG
*
*/
@LoadBalancerClients(defaultConfiguration = UnitLoadBalancerConfiguration.class)
public class UnitLoadBalanceAutoConfiguration {
}
参考:【SpringCloud系列】开发环境下重写Loadbalancer实现自定义负载均衡_红藕香残玉簟秋的博客-CSDN博客