开启生长之旅!这是我参加「日新计划 2 月更文应战」的第 11 天,点击检查活动概况

Spring Cloud版别假如Hoxton.M2 RELEASED版别之前的,Nacos Discovery默许是集成了Ribbon的,可是最新Alibaba-Nacos-DiscoveryHoxton.M2 RELEASED版别之后弃用了Ribbon,运用Spring Cloud Loadbalancer作为客户端的负载均衡组件。从Spring Cloud 2020版别开始,Spring Cloud移除了 Ribbon,运用Spring Cloud Loadbalancer作为客户端的负载均衡组件。

Nacos最新版别

1️⃣ Nacos 2021版别现已没有自带Ribbon的整合,所以需求引入另一个支撑的jarloadbalancer;
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发展渊源:

  • 2017Spring开始测验开发新的项目Spring Cloud LoadBalancer代替Ribbon,项目保管在spring-cloud-incubator孵化器
  • 经过N个月的时间,Spring突然将项目符号归档迁移到了Spring Cloud Common
  • 现在Spring Cloud Common最新版别为现已迭代至4.0.1

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

Spring Cloud LoadBalancer官方文档

Spring Cloud供给了自己的客户端负载均衡器笼统和完成。关于负载均衡机制,增加了ReactiveLoadBalancer接口,并供给了根据Round-RobinRandom的完成。为了从呼应式服务中挑选实例,运用了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
 *
 */
@Configuration
public class RestTemplateConfig {
    /**
     * 为restTemplate整合ribbon
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    /**
     * Ribbon 自带的负载均衡战略有如下几个:
     * 1.AvailabilityFilteringRule: 先过滤掉由于屡次拜访毛病而处于断路器跳闸状态的服务,以及并发连接数超过阈值的服务,剩下的服务,运用轮询战略
     * 2.BestAvailableRule: 先过滤掉由于屡次拜访毛病而处于断路器跳闸状态的服务,然后挑选一个并发量最小的服务
     * 3.ZoneAvoidanceRule: 复合判断 server 所在区域的性能和 server 的可用性挑选服务器
     * 4.RandomRule: 随机负载均衡
     * 5.RoundRibbonRule:轮询,人人有份
     * 6.RetryRule:先轮询,假如获取失败则在指定时间内重试,从头轮询可用的服务
     * 7.WeightedResponseTimeRule:根据平均呼应时间核算一切服务的权重,呼应越快的服务权重越高,越容易被选中。
     */
    @Bean
    public IRule myCustomRule() {
        //轮询战略负载均衡算法,人人有份
        return new RoundRobinRule();
    }
}

在注册bean的一起,增加@LoadBalanced负载均衡注解,赋予RestTemplate负载均衡才能,默许的负载均衡算法是:轮训办法

Spring Cloud LoadBalancer原理

LoadBalancerClient

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

public interface LoadBalancerClient extends ServiceInstanceChooser {
   <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()办法用来重构URLLoadBalancerClient的默许完成类为BlockingLoadBalancerClientBlockingLoadBalancerClient目标中存在两个choose()办法,别离完成重写了ServiceInstanceChooser的两个choose()办法。

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

ReactiveLoadBalancer

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

上图能够看出,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);
   default Mono<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
 */
public class CustomLoadBalancerConfiguration {
    /**
     * 自定义负载均衡战略(随机/轮训)
     *
     * @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})
public class CustomRestTemplateConfig {
    @Bean
    @LoadBalanced
    public 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 {
    public static void main(String[] args) {
        SpringApplication.run(MambaContentCenterApplication.class, args);
    }
}

✔此时,RestTemplate现已具有了负载均衡器的才能,选用的负载均衡战略为:轮训办法负载均衡,下面我以内容中心调用用户中心为例,测试Spring Cload LoadBalancer的轮训负载均衡战略是否收效,现在内容中心服务实例地址为:http://localhost:9081 用户中心服务别离发动了两个实例,实例1:http://localhost:8081,实例2:http://localhost:8082,现在内容中心经过调用用户中心获取用户信息,对应的Nacos注册的实例信息如下图所示:

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

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

2023-02-10 01:39:19.435 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] ---> GET http://user-center/users/1 HTTP/1.1
2023-02-10 01:39:19.435 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] ---> END HTTP (0-byte body)
2023-02-10 01:39:19.440 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] <--- HTTP/1.1 200 (5ms)
2023-02-10 01:39:19.441 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] connection: keep-alive
2023-02-10 01:39:19.441 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] content-type: application/json
2023-02-10 01:39:19.441 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] date: Thu, 09 Feb 2023 17:39:19 GMT
2023-02-10 01:39:19.441 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] keep-alive: timeout=60
2023-02-10 01:39:19.441 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] transfer-encoding: chunked
2023-02-10 01:39:19.441 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] 
2023-02-10 01:39:19.441 DEBUG 29144 --- [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 DEBUG 29144 --- [io-9081-exec-10] c.j.m.feignClient.UserCenterFeignClient  : [UserCenterFeignClient#findById] <--- END HTTP (194-byte body)

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

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

说明运用Spring Cloud Balancer装备的负载均衡规矩现已收效...

思考:

假如咱们想完成 同集群下优先调用 的负载均衡算法,根据上面两种设计思维,我供给了详细完成思路如下:

同集群下优先调用

  • 自定义负载均衡器NacosSameClusterPreferenceLoadBalancer
  • 运用NacosLoadBalancer自带的负载均衡战略(引荐)

完成思路:

  1. 先找到指定服务的一切实例instanceA
  2. 过滤出相同集群的一切实例instanceB
  3. 假如发现同集群的instanceB为空才跨集群调用instanceA
  4. 根据权重的负载均衡,回来1个可调用的健康实例。

总结

Spring Cloud LoadBalancerSpring 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更丰富。

好了,本篇文章介绍到此结束了,假如文章内容对你有所帮助,欢迎点赞+评论+保藏❤,我是:‍austin流程枫,咱们下期见~