Ribbon真的会被Spring Cloud Loadbalancer替代吗?

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 11 天,点击查看活动详情

Spring Cloud版本如果Hoxton.M2 RELEASED版本之前的,Nacos Discovery默认是集成了Ribbon的,但是最新Alibaba-Nacos-Discovery在Hoxton.M2 RELEASED版本之后弃用了Ribbon,使用Spring Cloud Loadbalancer作为客户端的负载均衡组件。从Spring Cloud 2020版本开始,Spring Cloud移除了 Ribbon,使用Spring Cloud Loadbalancer作为客户端的负载均衡组件。

Nacos最新版本

1️⃣ Nacos 2021版本已经没有自带Ribbon的整合,所以需要引入另一个支持的jar包loadbalancer;

2️⃣ Nacos 2021版本已经取消了对Ribbon的支持,所以无法通过修改Ribbon负载均衡的模式来实现Nacos提供的负载均衡模式。

使用nacos 2021.1版本实现负载均衡

2021.0.1版本的nacos-discovery移除了Ribbon依赖:

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2021.1</version></dependency>复制代码

这个包已经移除了Ribbon支持,如果需要实现负载均衡,官方推荐替代方案是采用Spring Cloud LoadBalancer,对应的依赖:

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

Spring Cloud LoadBalancer

Spring Cloud LoadBalancer发展渊源:

  • 目前Spring Cloud Common最新版本为已经迭代至4.0.1。

Spring Cloud LoadBalancer官方文档

Spring Cloud提供了自己的客户端负载均衡器抽象和实现。对于负载均衡机制,增加了ReactiveLoadBalancer接口,并提供了基于Round-Robin和Random的实现。为了从响应式服务中选择实例,使用了ServiceInstanceListSupplier。目前,我们支持基于服务发现的ServiceInstanceListSupplier实现,该实现使用类路径中可用的发现客户端从服务发现中检索可用实例。

可以通过设置spring.cloud.loadbalancer.enabled的值为false来禁用Spring Cloud LoadBalancer。

之前版本是通过以下方式实现负载均衡:

package com.jacklin.mamba.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * 配置RestTemplate
 *
 */@ConfigurationpublicclassRestTemplateConfig {

    /**
     * 为restTemplate整合ribbon
     */@Bean@LoadBalancedpublic RestTemplate restTemplate() {
        return new RestTemplate();
    }

    /**
     * Ribbon 自带的负载均衡策略有如下几个:
     * 1.AvailabilityFilteringRule: 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,以及并发连接数超过阈值的服务,剩下的服务,使用轮询策略
     * 2.BestAvailableRule: 先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
     * 3.ZoneAvoidanceRule: 复合判断 server 所在区域的性能和 server 的可用性选择服务器
     * 4.RandomRule: 随机负载均衡
     * 5.RoundRibbonRule:轮询,人人有份
     * 6.RetryRule:先轮询,如果获取失败则在指定时间内重试,重新轮询可用的服务
     * 7.WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应越快的服务权重越高,越容易被选中。
     */@Beanpublic IRule myCustomRule() {
        //轮询策略负载均衡算法,人人有份return new RoundRobinRule();
    }
}
复制代码

在注册bean的同时,添加@LoadBalanced负载均衡注解,赋予RestTemplate负载均衡能力,默认的负载均衡算法是:轮训方式

Spring Cloud LoadBalancer原理

LoadBalancerClient

LoadBalancerClient作为负载均衡客户端,用于进行负载均衡逻辑,从服务列表中选择出一个服务地址进行调用,其内部方法为:

publicinterfaceLoadBalancerClientextendsServiceInstanceChooser {

   <T> T execute(String serviceId, LoadBalancerRequest<T> request)throws IOException;

   <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request)throws IOException;

   URI reconstructURI(ServiceInstance instance, URI original);
}
复制代码

在LoadBalancerClient中存在两个executor()方法,都是用于执行请求的,reconstructURI()方法用来重构URL,LoadBalancerClient的默认实现类为BlockingLoadBalancerClient,BlockingLoadBalancerClient对象中存在两个choose()方法,分别实现重写了ServiceInstanceChooser的两个choose()方法。

ReactiveLoadBalancer

上图可以看出,ReactorLoadBalancer即可继承ReactiveLoadBalancer接口,默认情况下使用的ReactiveLoadBalancer实现是RoundRobinLoadBalancer。要切换到不同的实现,无论是选择的服务还是所有服务,都可以使用自定义LoadBalancer配置机制,通过查看源码,ReactiveLoadBalancer提供了choose方法:

public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> {

   /**
    * Choose the next server based on the load balancing algorithm.
    */@SuppressWarnings("rawtypes")
   Mono<Response<T>> choose(Request request);

   defaultMono<Response<T>> choose() {
      return choose(REQUEST);
   }

}
复制代码

ReactorServiceInstanceLoadBalancer

ReactorServiceInstanceLoadBalancer作为ReactiveLoadBalancer的实现,默认提供了两种不同的负载均衡器,分别是:RandomLoadBalancer(随机负载均衡器)和RoundRobinLoadBalancer(轮询负载均衡器),在需要自定义负载均衡规则的时候我们只需要通过实现ReactorServiceInstanceLoadBalancer,重写choose方法即可。

接下来,需要在新的版本上实现RestTemplate负载均衡策略调用,结合Spring官方案例,需要自定义LoadBalancer配置机制来实现负载均衡,首先自定义负载均衡策略配置:

  • 自定义负载均衡策略CustomLoadBalancerConfiguration

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.core.env.Environment;

/**
 * Spring Cloud LoadBalancer替代Ribbon实现 随机/轮训 方式负载均衡策略配置
 *
 * @author: austin
 * @since: 2023/2/4 15:14
 */publicclassCustomLoadBalancerConfiguration {

    /**
     * 自定义负载均衡策略(随机/轮训)
     *
     * @return ReactorLoadBalancer
     */@Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);           //随机//return new RoundRobinLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);     // 轮训
    }
}
复制代码

接着在RestTemplate配置上通过@LoadBalancerClient指定注入对应策略配置:

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * 配置我们自定义的LoadBalancer策略,注:这里的类为注入Bean的类,而非负载均衡的实现类
 *
 * @author austin
 * @date 2023/2/4 10:23
 */@Configuration@LoadBalancerClients(defaultConfiguration = {CustomLoadBalancerConfiguration.class})publicclassCustomRestTemplateConfig {

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

在内容中心服务启动类添加:@LoadBalancerClient(value = "CLOUD-CONTENT-CENTER-SERVICE", configuration = CustomRestTemplateConfig.class)

/**
 * 内容中心服务启动类
 *
 * @author austin
 */@MapperScan(basePackages = "com.jacklin.mamba.mapper")
@SpringBootApplication@EnableFeignClients@LoadBalancerClient(value = "CLOUD-CONTENT-CENTER-SERVICE", configuration = CustomRestTemplateConfig.class)
public class MambaContentCenterApplication {

    publicstaticvoidmain(String[] args) {
        SpringApplication.run(MambaContentCenterApplication.class, args);
    }

}
复制代码

✔此时,RestTemplate已经具备了负载均衡器的能力,采用的负载均衡策略为:轮训方式负载均衡,下面我以内容中心调用用户中心为例,测试Spring Cload LoadBalancer的轮训负载均衡策略是否生效,目前内容中心服务实例地址为:http://localhost:9081 用户中心服务分别启动了两个实例,实例1:http://localhost:8081,实例2:http://localhost:8082,现在内容中心通过调用用户中心获取用户信息,对应的Nacos注册的实例信息如下图所示:

访问:http://localhost:9081/post/1 , 查看内容中心控制台:

2023-02-10 01:39:19.435 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] --->GEThttp://user-center/users/1HTTP/1.12023-02-10 01:39:19.435 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] --->ENDHTTP(0-bytebody)2023-02-10 01:39:19.440 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] <---HTTP/1.1200(5ms)2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] connection:keep-alive2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] content-type:application/json2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] date:Thu,09Feb2023 17:39:19 GMT2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] keep-alive:timeout=602023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] transfer-encoding:chunked2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] 
2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] {"id":1,"wechat":"jacklin0828","nickname":"austin","roles":"admin","avatar":"https://w.wallhaven.cc/full/6o/wallhaven-6o6orw.png","createTime":"2021-12-16","updateTime":"2021-12-16","bonus":300}
2023-02-10 01:39:19.441 DEBUG29144--- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] <---ENDHTTP(194-bytebody)复制代码

观察用户中心服务的日志打印,不同实例分别被调用了5次:

说明使用Spring Cloud Balancer配置的负载均衡规则已经生效👏👏👏...

🤔思考:

如果我们想实现 同集群下优先调用 的负载均衡算法,基于上面两种设计思想,我提供了具体实现思路如下:

同集群下优先调用

  • 自定义负载均衡器NacosSameClusterPreferenceLoadBalancer

  • 利用NacosLoadBalancer自带的负载均衡策略(推荐)

实现思路:

  1. 先找到指定服务的所有实例instanceA

  1. 过滤出相同集群的所有实例instanceB

  1. 如果发现同集群的instanceB为空,才跨集群调用instanceA

  1. 基于权重的负载均衡,返回1个可调用的健康实例。

总结

Spring Cloud LoadBalancer与Spring Cloud Ribbon通过RestTemplate做负载均衡,他们之前的对比如下:

1️⃣ 都是使用LoadBalancerInterceptor作为RestTemplate的拦截器
2️⃣ 在LoadBalancerInterceptor中持有LoadBalancerClient对象,在Spring Cloud LoadBalancer中是BlockingLoadBalancerClient,在Spring Cloud Ribbon中是RibbonLoadBalancerClient
3️⃣ LoadBalancerClient中持有NamedContextFactory对象,在Spring Cloud LoadBalancer中是LoadBalancerClientFactory,在Spring Cloud Ribbon中是SpringClientFactory
4️⃣ Spring Cloud LoadBalancer通过实现ReactorServiceInstanceLoadBalancer接口自定义负载均衡器,Spring Cloud Ribbon通过实现ILoadBalancer接口
5️⃣ Spring Cloud LoadBalancer通过注解@LoadBalancerClient或@LoadBalancerClients实现自定义配置,Spring Cloud Ribbon也可以使用这两个注解,另外还可以使用@RibbonClient或@RibbonClients
6️⃣ Spring Cloud LoadBalancer支持响应式编程负载均衡,即结合Spring Web Flux使用,Spring Cloud Ribbon是不支持的
7️⃣ 目前Ribbon提供的负载均衡算法实现较Spring Cloud LoadBalancer更丰富。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值