在 2020 年以前的 SpringCloud 采用 Ribbon 作为负载均衡,但是 2020 年之后,SpringCloud 吧 Ribbon 移除了,而是使用自己编写的 LoadBalancer 替代.
1.排除客户端和openfeign中的ribbon包
-
-
com.alibaba.cloud -
spring-cloud-starter-alibaba-nacos-discovery -
-
-
org.springframework.cloud -
spring-cloud-netflix-ribbon -
-
-
-
-
-
-
org.springframework.cloud -
spring-cloud-starter-openfeign -
-
-
org.springframework.cloud -
spring-cloud-netflix-ribbon -
-
-
2.引入scl依赖
-
-
org.springframework.cloud -
spring-cloud-starter-loadbalancer -
到这里已经可以使用了,默认的负载方式就是轮询,那么如何自定义负载均衡策略呢
LoadBalancer默认提供了两种负载均衡策略:
现在希望修改默认的负载均衡策略为随机分配策略,就需要创建随机分配策略的配置类(不用加 @Configuration):
- //这里不用加 @Configuration 注解
- public class LoadBalancerConfig {
- //将官方提供的 RandomLoadBalancer 注册为Bean
- @Bean
- public ReactorLoadBalancer
randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory){ - String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
- return new RandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
- }
- }
通过 @LoadBalancerClient(value = "服务名", configuration = LoadBalancerConfig.class) 指定负载均衡策略为随机.
- @FeignClient("article")
- @LoadBalancerClient(value = "article", configuration = LoadBalancerConfig.class) //指定负载均衡策略为随机
- public interface ArticleClient {
-
- // @LoadBalanced(可以写,也可以不用写,默认所有方法都自动加 @LoadBalanced)
- @GetMapping("/article/start")
- String userStart();
-
- }
自定义负载均衡策略:可用于灰度发布
- /**
- * Description:
- * 自定义灰度
- * 通过给请求头添加Version 与 Service Instance 元数据属性进行对比
- * @author Jam
- * @date 2021/6/1 17:26
- */
- @Log4j2
- public class VersionGrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
-
- private final ObjectProvider
serviceInstanceListSupplierProvider; - private final String serviceId;
-
- private final AtomicInteger position;
-
- public VersionGrayLoadBalancer(ObjectProvider
serviceInstanceListSupplierProvider, String serviceId) { - this(serviceInstanceListSupplierProvider,serviceId,new Random().nextInt(1000));
- }
-
- public VersionGrayLoadBalancer(ObjectProvider
serviceInstanceListSupplierProvider, - String serviceId, int seedPosition) {
- this.serviceId = serviceId;
- this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
- this.position = new AtomicInteger(seedPosition);
- }
-
- @Override
- public Mono
> choose(Request request) { - ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
-
- return supplier.get(request).next()
- .map(serviceInstances -> processInstanceResponse(serviceInstances,request));
-
- }
-
-
- private Response
processInstanceResponse(List instances, Request request) { - if (instances.isEmpty()) {
- log.warn("No servers available for service: " + this.serviceId);
- return new EmptyResponse();
- } else {
- DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
- RequestData clientRequest = (RequestData) requestContext.getClientRequest();
- HttpHeaders headers = clientRequest.getHeaders();
-
- // get Request Header
- String reqVersion = headers.getFirst("version");
-
- if(StringUtils.isEmpty(reqVersion)){
- return processRibbonInstanceResponse(instances);
- }
-
- log.info("request header version : {}",reqVersion );
- // filter service instances
- List
serviceInstances = instances.stream() - .filter(instance -> reqVersion.equals(instance.getMetadata().get("version")))
- .collect(Collectors.toList());
-
- if(serviceInstances.size() > 0){
- return processRibbonInstanceResponse(serviceInstances);
- }else{
- return processRibbonInstanceResponse(instances);
- }
- }
- }
-
- /**
- * 负载均衡器
- * 参考 org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer#getInstanceResponse
- * @author javadaily
- */
- private Response
processRibbonInstanceResponse(List instances) { - int pos = Math.abs(this.position.incrementAndGet());
- ServiceInstance instance = instances.get(pos % instances.size());
- return new DefaultResponse(instance);
- }
-
- }
- /**
- * Description:
- * 自定义负载均衡器配置实现类
- * @author javadaily
- * @date 2021/6/3 16:02
- */
- public class VersionLoadBalancerConfiguration {
- @Bean
- ReactorLoadBalancer
versionGrayLoadBalancer(Environment environment, - LoadBalancerClientFactory loadBalancerClientFactory) {
- String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
- return new VersionGrayLoadBalancer(
- loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
- }
-
- }
VersionLoadBalancerConfiguration配置类不能添加@Configuration注解。
在网关启动类使用注解@LoadBalancerClient指定哪些服务使用自定义负载均衡算法
通过@LoadBalancerClient(value = "auth-service", configuration = VersionLoadBalancerConfiguration.class),对于auth-service启用自定义负载均衡算法;
或通过@LoadBalancerClients(defaultConfiguration = VersionLoadBalancerConfiguration.class)为所有服务启用自定义负载均衡算法。