微服务之SpringCloud LoadBalancer

SpringCloud LoadBalancer

  • 1 简介
  • 2 使用步骤(Eureka+LoadBalancer)
    • 2.1 引入pom.xml
    • 2.2 自定义负载均衡算法(MyLoadBalancer.java)
    • 2.3 选择负载均衡算法(CustomLoadBalancerConfiguration.java)
    • 2.4 整合Eureka(ApplicationContextConfig.java)
    • 2.5 自定义负载均衡算法效果


入门网址→入门

1 简介

  • SpringCloud原有的客户端负载均衡方案Ribbon已经被废弃,取而代之的是SpringCloud LoadBalancer。
  • 相比较于Ribbon,Spring Cloud LoadBalancer不仅能够支持RestTemplate,还支持WebClient。WeClient是Spring Web Flux中提供的功能,可以实现响应式异步请求,因此学习Spring Cloud LoadBalancer之前,建议先了解下Spring Web Flux。

2 使用步骤(Eureka+LoadBalancer)

微服务之SpringCloud LoadBalancer_第1张图片

2.1 引入pom.xml

Eureka 自带了 spring-cloud-starter-loadbalancer ,如果没自带自行引入

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-loadbalancerartifactId>
    <version>3.1.1version>
dependency>

2.2 自定义负载均衡算法(MyLoadBalancer.java)

//这个方法基本是copy的RandomLoadBalancer自己改一改出来的
public class MyLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(MyLoadBalancer.class);

    final AtomicInteger position;//请求的次数

    final String serviceId; //服务名称 用于提示报错信息的

    private int flag = 0; //定义计数器

    //两个参数的构造方法 需要服务名称和实例提供者 这个在方法中传递进来
    public MyLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
                          String serviceId) {
        //如果不传请求次数就自己初始化 反正每次都+1
        this(new Random().nextInt(100), serviceId, serviceInstanceListSupplierProvider);
    }

    public MyLoadBalancer(int seedPosition, String serviceId, ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
        this.position = new AtomicInteger(seedPosition);
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        //从服务提供者中获取到当前request请求中的serviceInstances并且遍历
        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 = 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 (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
        //pos是当前请求的次数 这样可以自定义负载均衡的切换  这个每次+1的操作是复制的 最好是不删
        Integer pos = Math.abs(this.position.incrementAndGet());

        if (pos >= 2147483647) pos = 0;

        if (pos % 3 == 0) {
            //是3的倍数就切换
            flag = pos % instances.size();
        }
        //主要的就是这句代码设置负载均衡切换
        ServiceInstance instance = instances.get(flag);
        return new DefaultResponse(instance);
    }
}

2.3 选择负载均衡算法(CustomLoadBalancerConfiguration.java)

The classes you pass as @LoadBalancerClientor @LoadBalancerClients configuration arguments should either not be annotated with @Configurationor be outside component scan scope.

翻译:作为@LoadBalancerClient或@LoadBalancerClients配置参数传递的类要么不应该带有@Configuration注释,要么应该在组件扫描范围之外。

public class CustomLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        //LoadBalancer自带的负载均衡算法只有两个:随机算法和轮询算法
        
        //选择随机算法
        // return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);

        //选择自定义负载均衡算法
        return new MyLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

2.4 整合Eureka(ApplicationContextConfig.java)

添加注解:@LoadBalancerClient(value = "CLOUD-PAYMENT-SERVICE", configuration = CustomLoadBalancerConfiguration.class)

@Configuration
@LoadBalancerClient(value = "CLOUD-PAYMENT-SERVICE", configuration = CustomLoadBalancerConfiguration.class)
public class ApplicationContextConfig {

    /**
     * RestTemplate的作用是完成微服务之间的调用
     * @return
     */

    @Bean  //依赖注入
    @LoadBalanced //对payment8090和对payment8091负载均衡
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

2.5 自定义负载均衡算法效果

每三次切换一次服务器

你可能感兴趣的:(Spring,spring,cloud,eureka,负载均衡)