内置负载均衡器的源码分析

Spring Cloud LoadBalancer 内置了两个负载均衡器,都实现自 ReactorServiceInstanceLoadBalancer 接口,分别使用了轮询算法和随机算法。默认采用的是使用了轮询算法的 RoundRobinLoadBalancer 类,源码及源码注释如下:

package org.springframework.cloud.loadbalancer.core;

public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    已省略部分代码

    @SuppressWarnings("rawtypes")
    @Override

    public Mono<Response<ServiceInstance>> choose(Request request) {
        // 获取可用的实例提供者 ServiceInstanceListSupplier
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
                .getIfAvailable(NoopServiceInstanceListSupplier::new);
        // 封装获取实例的逻辑
        return supplier.get(request).next()
                .map(serviceInstances -> processInstanceResponse(supplier,
                        serviceInstances));
    }

    private Response<ServiceInstance> processInstanceResponse(
            ServiceInstanceListSupplier supplier, List<ServiceInstance>
                    serviceInstances) {
        // 根据轮询算法获取一个可用的服务实例信息
        Response<ServiceInstance> serviceInstanceResponse = getInstance
                (serviceInstances);
        if (supplier instanceof SelectedLoadBalancerCallback && serviceInstance
        Response.hasServer()){
            ((SelectedLoadBalancerCallback) supplier).selectedServiceInstance
                    (serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstance(List<Service
                                                          Instance>instances) {
        // 判空
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
        // 有一个 AtomicInteger 类型的 position 变量,从 ServiceInstanceListSupplier
        // 中获取所有可用的实例列表,之后将 position 加 1,对列表大小取模,返回列表中这个位置的服务
        // 实例 ServiceInstance
        int pos = Math.abs(this.position.incrementAndGet());

        ServiceInstance instance = instances.get(pos % instances.size());

        return new DefaultResponse(instance);
    }
}

这个负载均衡器的实现很简单,有一个 AtomicInteger 原子类型的 position 变量,从 ServiceInstanceListSupplier 中读取所有可用的实例列表,之后将 position 加 1,对列表大小取模,返回列表中这个位置的服务实例 ServiceInstance,是非常标准的轮询算法。