自定义负载均衡算法
下面笔者结合实际的编码实现一个自定义的负载均衡算法,并使用该负载均衡器来测试负载均衡的效果。
在 ltd.newbee.cloud
包下新建 balancer
包,并新建 NewBeeCloudLoadBalancer
类。注意,该类一定要实现 ReactorServiceInstanceLoadBalancer
接口,源码如下:
package ltd.newbee.cloud.balancer;
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.client.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.client.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class NewBeeCloudLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider
{
private String serviceName;
public
NewBeeCloudLoadBalancer(ObjectProvider < ServiceInstanceListSupplier > serviceInstanceListSupplierProvider, String serviceName)
{
this.serviceName = serviceName;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
}
private AtomicInteger atomicCount = new AtomicInteger(0);
private AtomicInteger atomicCurrentIndex = new AtomicInteger(0);
@Override
public Mono<Response<ServiceInstance>> choose (Request request){
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable();
return supplier.get().next().map(this::getInstanceResponse);
}
/**
* 使用自定义方法获取服务
*
* @param instances
* @return
*/
private Response<ServiceInstance> getInstanceResponse (
List < ServiceInstance > instances) {
ServiceInstance serviceInstance = null;
if (instances.isEmpty()) {
System.out.println("注册中心无可用的实例:" + serviceName);
return new EmptyResponse();
}
//累加并得到值(请求次数)
int requestNumber = atomicCount.incrementAndGet();
//自定义算法
if (requestNumber < 2) {
serviceInstance = instances.get(atomicCurrentIndex.get());
} else {
// 已经大于了2了,重置
atomicCount = new AtomicInteger(0);
// atomicCurrentIndex 变量加1
atomicCurrentIndex.incrementAndGet();
if (atomicCurrentIndex.get() >= instances.size()) {
atomicCurrentIndex = new AtomicInteger(0);
serviceInstance = instances.get(instances.size() - 1);
return new DefaultResponse(serviceInstance);
}
// 从可用的实例中获取一个实例来进行操作,类似轮询算法
serviceInstance = instances.get(atomicCurrentIndex.get() - 1);
}
return new DefaultResponse(serviceInstance);
}
@Override
public Mono<Response<ServiceInstance>> choose () {
return ReactorServiceInstanceLoadBalancer.super.choose();
}
}
自定义的负载均衡算法与轮询算法类似,不过并不是执行一次请求就使用下一个实例,而是每个实例执行两次才会轮询到下一个实例,该值由 atomicCount
变量控制。
自定义的负载均衡算法编写完成后,还需要做一次配置才能使用。在 config
包中新建配置类 NewBeeCloudLoadBalancerConfiguration
,源码如下:
package ltd.newbee.cloud.config;
import ltd.newbee.cloud.balancer.NewBeeCloudLoadBalancer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
public class NewBeeCloudLoadBalancerConfiguration {
@Bean
public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new NewBeeCloudLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
需要在启动类上添加一个 @LoadBalancerClient
注解,将该配置类和目标服务做好关联。启动类代码改动如下:
@SpringBootApplication
@EnableDiscoveryClient
//对 newbee-cloud-goods-service 服务使用自定义的负载均衡算法
@LoadBalancerClient(value = "newbee-cloud-goods-service", configuration = NewBeeCloudLoadBalancerConfiguration.class)
public class LoadBalancerApplication {
public static void main(String[] args) {
SpringApplication.run(LoadBalancerApplication.class, args);
}
}
最后,重启项目并测试效果,自定义负载均衡算法编码完成。