内置负载均衡器的源码分析
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
,是非常标准的轮询算法。