跳转至

LoadBalancer支持哪些负载均衡策略?如何修改?

典型回答

Spring Cloud LoadBalancer 内置其实只提供了以下2种默认策略:

策略 描述
轮询 (Round-Robin) RoundRobinLoadBalancer 默认策略,每个请求依次分配到不同的实例
随机 (Random) RandomLoadBalancer 随机选择一个可用实例

默认情况下,Spring Cloud LoadBalancer 使用RoundRobinLoadBalancer 进行轮询调度(向下兼容了Ribbon的轮询策略),即请求会依次轮流分配到可用的服务实例。 定义在LoadBalancerClientConfiguration 中:

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {

    @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);
    }
}

以上,就可以看到,这里是使用了RoundRobinLoadBalancer来作为默认的负载均衡策略的。

如果想要修改负载均衡策略,需要自己定义 ReactorLoadBalancer<ServiceInstance> Bean。 比如使用随机策略:

@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                               LoadBalancerClientFactory clientFactory) {
    String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    return new RandomLoadBalancer(clientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}

扩展知识

Nacos负载均衡策略使用

当然,除了默认的这两种之外,其实我们还可以用其他的负载均衡策略,比如Nacos提供的 NacosLoadBalancer,用如下方式即可开启Nacos的负载均衡策略了。

@Bean
public ReactorLoadBalancer<ServiceInstance> nacosLoadBalancer(Environment environment,
                                                              LoadBalancerClientFactory clientFactory) {
    String serviceId = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    return new NacosLoadBalancer(clientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class), serviceId);
}

自定义负载均衡策略

Spring Cloud LoadBalancer 中自定义负载均衡策略,通常需要实现 ReactorServiceInstanceLoadBalancer 接口,并在其中自定义实例选择逻辑。Spring Cloud LoadBalancer 会根据你的负载均衡策略来决定如何选择服务实例。

1、 实现 ReactorServiceInstanceLoadBalancer

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.client.loadbalancer.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.client.loadbalancer.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class CustomLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final ServiceInstanceListSupplier serviceInstanceListSupplier;

    public CustomLoadBalancer(ServiceInstanceListSupplier serviceInstanceListSupplier) {
        this.serviceInstanceListSupplier = serviceInstanceListSupplier;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        return serviceInstanceListSupplier.get().next().map(serviceInstances -> {
            // 自定义负载均衡逻辑
            // 这里可以是轮询、最小请求次数、加权策略等
            ServiceInstance chosenInstance = chooseByMinRequestCount(serviceInstances);
            return new DefaultResponse(chosenInstance);
        });
    }

    /**
     * 按最少请求次数选择实例(示例策略)
     */
    private ServiceInstance chooseByMinRequestCount(List<ServiceInstance> serviceInstances) {
        // 这里可以使用计数器或者负载均衡逻辑进行选择,示例为选择第一个
        return serviceInstances.get(0); 
    }
}

2、 配置自定义负载均衡器。

import org.springframework.cloud.client.loadbalancer.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.client.loadbalancer.ServiceInstanceListSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LoadBalancerConfig {

    @Bean
    public ReactorServiceInstanceLoadBalancer customLoadBalancer(ServiceInstanceListSupplier serviceInstanceListSupplier) {
        return new CustomLoadBalancer(serviceInstanceListSupplier);
    }
}