springcloud自定义负载均衡LoadBalancer

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博客

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值