spring cloud新版本使用loadbalancer替代Ribbon

Nacos 2021 不再集成 Ribbon,建议使用spring cloud loadbalancer

引入

一、简单使用

引入依赖spring cloud loadbalancer

复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

RestTemplate集成

启动类的restTemplate bean方法添加@LoadBalanced注解

复制代码
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

二、修改默认负载均衡方式

Spring Cloud Balancer中实现了轮询RoundRobinLoadBalancer和随机数RandomLoadBalancer两种负载均衡算法

默认情况下的负载均衡为轮询RoundRobinLoadBalancer

如果我们需要改成随机RandomLoadBalancer,可以自定义

新建文件 CustomLoadBalancerConfiguration.java

复制代码
package com.itmuch.contentcenter.rule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.loadbalancer.NacosLoadBalancer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
public class CustomLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> loadBalancer(Environment environment,
                                                      LoadBalancerClientFactory loadBalancerClientFactory, NacosDiscoveryProperties nacosDiscoveryProperties) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);


        //轮询加载,默认就是这个
        /*return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
                ServiceInstanceListSupplier.class),name);*/

        //返回随机轮询负载均衡方式
        return new RandomLoadBalancer(loadBalancerClientFactory.
                getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);

        //nacos的负载均衡策略,按权重分配
        /*return new NacosLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
                ServiceInstanceListSupplier.class),
                name, nacosDiscoveryProperties);*/
    }
}

然后在启动类加注解@LoadBalancerClient,参数name为spring.application.name,configuration为上面自定义的类

复制代码
package com.itmuch.contentcenter;

import com.itmuch.contentcenter.rule.CustomWeightLoadBalancerConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import tk.mybatis.spring.annotation.MapperScan;

// 扫描mybatis哪些包里面的接口
@MapperScan("com.itmuch")
@SpringBootApplication
@LoadBalancerClient(name = "user-center",configuration = CustomLoadBalancerConfiguration.class)
public class ContentCenterApplication {

    public static void main(String[] args) {
        SpringApplication.run(ContentCenterApplication.class, args);
    }

    //在spring容器装载哪一个对象,类型为RestTemplate 名称为restTemplate
    // <bean id="restTemplate" clase ="xxx.xxx.RestTemplate"
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

三、自定义负载均衡策略

如果我们想自定义策略。可以参考RoundRobinLoadBalancer类自己实现

以下为调3次轮换的自定义策略

CustomWeightLoadBalancerConfiguration.java

复制代码
package com.itmuch.contentcenter.rule;

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.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
public class CustomWeightLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> weightloadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

        //返回自定义负载均衡方式
        return new WeightLoadBalancer(loadBalancerClientFactory.
                getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);

    }
}

WeightLoadBalancer.java

核心在于重载实现ReactorServiceInstanceLoadBalancer类的choose方法

复制代码
package com.itmuch.contentcenter.rule;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;

import java.util.List;

public class WeightLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(WeightLoadBalancer.class);
    private int total = 0;    // 被调用的次数
    private int index = 0;    // 当前是谁在提供服务

    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private String serviceId;

    public WeightLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.serviceId = serviceId;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable();
        return supplier.get().next().map(this::getInstanceResponse);
    }

    //每个服务访问3次,然后换下一个服务
    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        log.info("进入自定义负载均衡");
        if (instances.isEmpty()) {
            return new EmptyResponse();
        }

        log.info("每个服务访问3次后轮询");
        int size = instances.size();

        ServiceInstance serviceInstance = null;
        while (serviceInstance == null) {
            System.out.println("===");
            if (total < 3) {
                serviceInstance = instances.get(index);
                total++;
            } else {
                total = 0;
                index++;
                if (index >= size) {
                    index = 0;
                }
                serviceInstance = instances.get(index);
            }
        }
        return new DefaultResponse(serviceInstance);
    }


}

最后跟上面一样,启动类加注解@LoadBalancerClient,指向自定义的config

复制代码
@LoadBalancerClient(name = "user-center",configuration = CustomWeightLoadBalancerConfiguration.class)

四、使用nacos的负载均衡策略

在nacos定义了负载均衡策略类NacosLoadBalancer,我们可以直接使用

使用配置类方式

复制代码
package com.itmuch.contentcenter.rule;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.loadbalancer.NacosLoadBalancer;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

@Configuration
public class CustomLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> loadBalancer(Environment environment,
                                                      LoadBalancerClientFactory loadBalancerClientFactory, NacosDiscoveryProperties nacosDiscoveryProperties) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);


        //nacos的负载均衡策略,按权重分配
        return new NacosLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
                ServiceInstanceListSupplier.class),
                name, nacosDiscoveryProperties);
    }
}

然后还是启动类加注解@LoadBalancerClient,指向自定义的config

复制代码
@LoadBalancerClient(name = "user-center",configuration = CustomLoadBalancerConfiguration.class)

配置文件方式

复制代码
#开启nacos的负载均衡策略
spring.cloud.loadbalancer.nacos.enabled=true

如果需要根据nacos的权重进一步自定义,可参考NacosLoadBalancer的代码自己实现

可参考Nacos负载均衡策略_nacos负载均衡策略配置_carroll18的博客-CSDN博客

相关推荐
瀚高PG实验室2 分钟前
因磁盘IO性能低导致程序An I/O error 报错
java·jvm·数据库·瀚高数据库
好家伙VCC5 分钟前
**发散创新:基于FFmpeg的视频编码优化实践与实战代码解析**在现代多媒体系统中,
java·python·ffmpeg·音视频
SamDeepThinking6 分钟前
开篇词:6000万会员规模下,我们是怎么做秒杀系统的
java·后端·架构
程序员书虫20 分钟前
Spring 依赖注入一次讲透:`@Autowired`、`@Resource`、`@Qualifier`、`@Primary` 到底怎么选
java·后端·面试
Rsun0455131 分钟前
16、Java 迭代器模式从入门到实战
java·开发语言·迭代器模式
quan263135 分钟前
20260416,日常开发-再记一次内存溢出
java·内存溢出·jprofile
布吉岛的石头35 分钟前
线上服务凌晨OOM:一次因「无超时设置」引发的内存雪崩复盘
java
SamDeepThinking37 分钟前
Spring Bean作用域的设计与使用
java·后端·面试
Flittly39 分钟前
【SpringSecurity新手村系列】(2)整合 MyBatis 实现数据库认证
java·安全·spring·springboot·安全架构
Oliver_LaVine1 小时前
java项目启动报错:CreateProcess error=206, 文件名或扩展名太长
java·linux·jenkins