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的代码自己实现