科普文:微服务之Spring Cloud 客户端负载均衡组件LoadBalancer替换Ribbon ...

打印 上一主题 下一主题

主题 904|帖子 904|积分 2712

概叙

负载均衡


负载均衡的两个根本点


  • 选择哪个服务器来处理客户端哀求。
  • 将客户端哀求转发出去。
一个核心原理:通过硬件或软件的方式维护一个服务列表清单。当用户发送哀求时,会将哀求发送给负载均衡器,然后根据负载均衡算法从可用的服务列表中选出一台服务器的地点,将哀求进行转发,完成负载功能。
科普文:深入理解负载均衡(四层负载均衡、七层负载均衡)-CSDN博客
负载均衡的特性

高性能:可根据差别的分配规则主动将流量进行分摊。
可扩展性:可以很方便增加集群中设备或链路的数量。
高可靠性:体系中某个设备或链路发生故障,不会导致服务制止。
易配置性:配置和维护方便。
透明性:用户感知不到如何进行负载均衡的,也不消关心负载均衡。
负载均衡策略

我们来看下这些负载均衡器如何通过负载均衡策略来选择服务器处理客户端哀求。
常见的均衡策略如下4种,其他另有


  • 最少毗连数Least Connection、
  • 源 IP 哈希Source IP Hash、
  • 最少毗连数慢启动时间Least Connection Slow Start Time、
  • 加权最少毗连Weighted Least Connection、
  • 固定权重Fixed Weighted、
  • 加权相应Weighted Response等等就不再介绍。
1 轮循均衡(Round Robin)

原理:假如给服务器从 0 到 N 编号,轮询均衡策略会从 0 开始依次选择一个服务器作为处理本次哀求的服务器。-
场景:适合所有父亲都有相同的软硬件配置,且哀求频率相对均衡。
2 权重轮询均衡(Weighted Round Robin)

原理:按照服务器的差别处理本领,给服务器分配差别的权重,然后哀求会按照权重分配给差别的服务器。
场景:服务器的性能差别,充实使用高性能的服务器,同时也能照顾到低性能的服务器。
3 随机均衡(Random)

原理:将哀求随机分配给差别的服务器。
场景:适合客户端哀求的频率比力随机的场景。
4 相应速度均衡(Response Time)

原理:负载均衡设备对每个服务器发送一个探测哀求,看看哪台服务器的相应速度更快,
场景:适合服务器的相应性能不断变革的场景。
注意:相应速度是针对负载均衡设备和服务器之间的。
负载均衡分类

负载均衡技术可以按照软件或硬件进行分类,也可以按照服务器列表存放的位置分别为服务端负载和客户端负载均衡。
1 硬件负载均衡

F5 就是常见的硬件负载均衡产物。
优点:性能稳固,具备很多软件负载均衡不具备的功能,如应用互换,会话互换、状态监控等。
缺点:设备价格昂贵、配置冗余,没有软件负载均衡灵活,不能满足定制化需求。
2 软件负载均衡

Nginx:性能好,可以负载超过 1W。工作在网络的7层之上,可以针对http应用做一些分流的策略。Nginx也可作为静态网页和图片服务器。Nginx仅能支持http、https和Email协议。
LVS(Linux Virtual Server):是一个虚拟服务器集群体系,接纳 IP 地点均衡技术和内容哀求分发技术实现负载均衡。接近硬件设备的网络吞吐和毗连负载本领。抗负载本领强、是工作在网络4层之上仅作分发之用。自身有完整的双机热备方案,如LVS+Keepalived。软件本身不支持正则表达式处理,不能做动静分离。
3 服务端负载均衡

Nginx 和 F5 都可以分别到服务端的负载均衡内里,后端的服务器地点列表是存储在后端服务器中大概存在专门的 Nginx 服务器或 F5 上。
服务器的地点列表的泉源是通过注册中心大概手动配置的方式来的。
4 客户端负载均衡

终于轮到 Ribbon 登场了,它属于客户端负载均衡器,客户端本身维护一份服务器的地点列表。这个维护的工作就是由 Ribbon 来干的。
Ribbon 会从 Eureka Server 读取服务信息列表,存储在 Ribbon 中。假如服务器宕机了,Ribbon 会从列表剔除宕机的服务器信息。
Ribbon 有多种负载均衡算法,我们可以自行设定规则从而哀求到指定的服务器。


OpenFeign底层默认负载均衡器Ribbon:RoundRobinRule

OpenFeign 底层使用的是 Ribbon 做负载均衡的,查看源码我们可以看到它默认的负载均衡策略是轮询策略:

然而除了轮询策略之外,我们另有其他 6 种内置的负载均衡策略可以选择,这些负载均衡策略如下:

  • RoundRobinRule(轮询策略,按照服务次序依次循环调用,默认负载均衡策略)
  • 权重策略:WeightedResponseTimeRule,根据每个服务提供者的相应时间分配一个权重,相应时间越长,权重越小,被选中的可能性也就越低。它的实现原理是,刚开始使用轮询策略并开启一个计时器,每一段时间收集一次所有服务提供者的均匀相应时间,然后再给每个服务提供者附上一个权重,权重越高被选中的概率也越大。
  • 最小毗连数策略:BestAvailableRule,也叫最小并发数策略,它是遍历服务提供者列表,选取毗连数最小的⼀个服务实例。假如有相同的最小毗连数,那么会调用轮询策略进行选取。
  • 地区敏感策略:ZoneAvoidanceRule,根据服务所在地区(zone)的性能和服务的可用性来选择服务实例,在没有地区的环境下,该策略和轮询策略类似。
  • 可用敏感性策略:AvailabilityFilteringRule,先过滤掉非健康的服务实例,然后再选择毗连数较小的服务实例。
  • 随机策略:RandomRule,从服务提供者的列表中随机选择一个服务实例。
  • 重试策略:RetryRule,按照轮询策略来获取服务,假如获取的服务实例为 null 或已经失效,则在指定的时间之内不断地进行重试来获取服务,假如超过指定时间依然没获取到服务实例则返回 null。
出于性能方面的考虑,我们可以选择用权重策略或地区敏感策略来替换轮询策略,因为这样的实行效率最高。

ribbon配置服务策略

全局策略设置

使用以下方式配置的策略表现对该项目中调用的所有服务生效。
  1. @Configuration
  2. public class MyConfiguration{
  3.     @Bean
  4.     public IRule ribbonRule(){
  5.         return new RandomRule();
  6.     }
  7.    
  8.     //定义一个负载均衡的RestTemplate
  9.     @Bean
  10.     @LoadBalanced
  11.     public RestTemplate restTemplate(){
  12.         return new RestTemplate();
  13.     }
  14. }
复制代码
上面的配置表现:

  • 定义了一个随机方式的服务调用方式,即随即调用某个服务的提供者;
  • 定义一个负载均衡的 RestTemplate,使用了 @LoadBalanced注解,该注解配合覆盖均衡策略一起使用 RestTemplate 发出的哀求才能生效。
RestTemplate是 Spring 提供的用于访问Rest服务的客户端模板工具集,Ribbon并没有创建新轮子,基于此通过负载均衡配置发出HTTP哀求。
局部策略设置

假如在项目中你想对某些服务使用指定的负载均衡策略,那么可以如下配置:
  1. @Configuration
  2. @RibbonClients({
  3.         @RibbonClient(name = "user-service",configuration = UserServiceConfig.class),
  4.             @RibbonClient(name = "order-service",configuration = OrderServiceConfig.class)
  5. })
  6. public class RibbonConfig {
  7. }
复制代码
@RibbonClients 中可以包含多个@RibbonClient。每个@RibbonClient表现一个服务名,背面临应的类表现该服务配套的策略规则。
假如你只想对一个服务应用某种规则,那么可以省略:@RibbonClients:
  1. @Configuration
  2. @RibbonClient(name = "order-service",configuration = OrderServiceConfig.class)
  3. public class RibbonConfig {
  4. }
复制代码
超时重试

HTTP哀求不免的会有网络欠好的环境出现超时,Ribbon提供了超时重试机制,提供如下参数可以设置:

饥饿加载

Ribbon在进行客户端负载均衡的时候并不是在启动的时候就加载上下文的,实在实际哀求的时候才加载,有点像servlet的第一次哀求的时候才去天生实例,这会导致第一次哀求会比力的迟钝,甚至可能会出现超时的环境。所以我们可以指定具体的客户端名称来开启饥饿加载,即在启动的时候便加载素养的配置项的应用上下文。

来一个本地全量配置:nacos+ribbon+openFeign


Ribbon负载均衡原理


Ribbon作为客户端负载均衡的工作原理可以概括为以下几个步骤:
参考:6000字 | 深入理解 Ribbon 的架构原理(文末送会员)-腾讯云开发者社区-腾讯云
Ribbon工作原理源码流程


  • 初始化:Ribbon启动时,会加载配置的服务列表。
    依旧是以前的逻辑找主动装配类,进入spring-cloud-starer-loadbalnecer:2.2.6.REALEAS,查找spring.factories,发现内里并没有对应spring.factories,这分析的这个starter只是起到jar管理的作用(查看的mybatis和SpringBoot整合的源码的话,会发现也是这样),所以进入pom中会发现应该是在spring-cloud-loadbalancer内里。

    分析这里主动配置类BlockingLoadBalancerClientAutoConfiguration和刚才分析的BlockingLoadBalancerClient前边名称一样,那这个应该是重点分析的主动配置类
    进入BlockingLoadBalancerClientAutoConfiguration,会发现这里和Ribbon中的配置相似,都是在LoadBalancerAutoConfiguration之前。

  • 负载均衡:Ribbon会根据预定的规则(如轮询、随机或最少活泼毗连数)选择一个服务实例。
           RestTemplate发送哀求肯定经过LoadBalancerInterceptor,中的intercept方法,这里loadBalancer是BlockingLoadBalancerClient
       

       

    获取服务列表选择服务完成调用

  • 服务调用:Ribbon将哀求发送到选定的服务实例。
  • 服务调用结果:原路返回。
上图可以体现出客户端负载均衡:即应用程序通过Ribbon从注册中心同步服务列表,然后在客户端通过配置的负载均衡策略IRrule进行服务调用。
Ribbon工作原理源码流程美满流程图

看网友的图 更直接。




Ribbon示例

一个 Eureka Server,3个Eureka Client,一个集成了Ribbon 的Consumer。

简单说一下关于 Ribbon consumer的配置:
pom文件中需要引入关于Ribbon的包,同时consumer也是一个Eureka Client要去拉 Eureka Server的配置,所以需要Eureka client的包。
  1. <dependency>
  2.     <groupId>org.springframework.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  4. </dependency>
  5. <dependency>
  6.     <groupId>org.springframework.cloud</groupId>
  7.     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  8. </dependency>
复制代码
在启动类中初始化了两个bean:
  1. import com.netflix.loadbalancer.IRule;
  2. import com.netflix.loadbalancer.RandomRule;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  6. import org.springframework.cloud.client.loadbalancer.LoadBalanced;
  7. import org.springframework.context.annotation.Bean;
  8. import org.springframework.web.client.RestTemplate;
  9. @EnableDiscoveryClient
  10. @SpringBootApplication
  11. public class RibbonDemoApplication {
  12.     public static void main(String[] args) {
  13.         SpringApplication.run(RibbonDemoApplication.class, args);
  14.     }
  15.     @Bean
  16.     @LoadBalanced
  17.     RestTemplate restTemplate() {
  18.         return new RestTemplate();
  19.     }
  20.     @Bean
  21.     public IRule ribbonRule() {
  22.         return new RandomRule();//这里配置策略,和配置文件对应
  23.     }
  24. }
复制代码
RestTemplate 和 IRule负载均衡策略。
然后就可以使用已经配置了负载均衡的 RestTemplate 发起哀求了:
  1. @Service
  2. public class DemoService {
  3.     @Autowired
  4.     RestTemplate restTemplate;
  5.     public String hello(String name) {
  6.         return restTemplate.getForEntity("http://eureka-client/hello/" + name, String.class).getBody();
  7.     }
  8. }
复制代码
Ribbon其他机制

服务端负载均衡的代表性例子就是nginx,LVS。那么客户端的负载均衡就是我们要说的Ribbon。Ribbon主要提供客户端负载均衡算法,除此之外,Ribbon还提供:


  • 服务发现集成 :功能区负载均衡器在动态环境(如云)中提供服务发现。功能区库中包含与Eureka和Netflix服务发现组件的集成;
  • 容错 : Ribbon API可以动态确定服务器是否已在实时环境中启动并运行,而且可以检测到那些已关闭的服务器;
  • 可配置的负载均衡规则 : Ribbon支持开箱即用的RoundRobinRuleAvailabilityFilteringRuleWeightedResponseTimeRule,还支持定义自定义规则。
Ribbon核心组件

Ribbon API提供以下组件供我们使用:

  • Rule :定义负载均衡策略;Ribbon 的负载均衡策略和之前讲过的负载均衡策略有部分相同。7中策略详见上一章节。
  • Ping : 定义如何ping目标服务实例来判断是否存活, ribbon使用单独的线程每隔一段时间(默认10s)对本地缓存的ServerList做一次查抄;实现类主要有这几个:PingUrl、PingConstant、NoOpPing、DummyPing、NIWSDiscoveryPing。心跳检测策略对象 IPingStrategy,默认实现是轮询检测。
  • ServerList :定义如何获取服务实例列表. 两种实现基于配置的ConfigurationBasedServerList和基于Eureka服务发现的DiscoveryEnabledNIWSServerList;

    • ServerList 主要用来获取所有服务的地点信息,并存到本地。
    • 根据获取服务信息的方式差别,又分为静态存储和动态存储。
    • 静态存储:从配置文件中获取服务节点列表并存储到本地。
    • 动态存储:从注册中心获取服务节点列表并存储到本地

  • ServerListFilter: 用来使用期望的特性过滤静态配置动态获得的候选服务实例列表. 若未提供, 默认使用ZoneAffinityServerListFilter;

    • 通过 Eureka 的分区规则对服务实例进行过滤。
    • 比力服务实例的通讯失败数和并发毗连数来剔除不够健康的实例。
    • 根据所属地区过滤出同地区的服务实例。

  • ILoadBalancer: 定义了软负载均衡器的操作的接口. 一个典型的负载均衡器至少需要一组用来做负载均衡的服务实例, 一个标记某个服务实例不在旋转中的方法, 和对应的方法调用从实例列表中选出某一个服务实例;用于管理负载均衡的组件。初始化的时候通过加载 YMAL 配置文件创建出来的。
  • ServerListUpdater: DynamicServerListLoadBalancer用来更新实例列表的策略(推EurekaNotificationServerListUpdater/拉PollingServerListUpdater, 默认是拉) 服务列表更新就是 Ribbon 会从注册中心获取最新的注册表信息。是由这个接口 ServerListUpdater 定义的更新操作。而它有两个实现类,也就是有两种更新方式:

    • 通过定时任务进行更新。由这个实现类 PollingServerListUpdater 做到的。
    • 使用 Eureka 的事件监听器来更新。由这个实现类 EurekaNotificationServerListUpdater 做到的。

  • RibbonClientConfiguration :RibbonClientConfiguration 类中通过 LoadBalancer,我们知道 ribbon 是靠LoadBalancer 做负载的 无非就是 ILoadBalancer 接口的方法,依次是添加新的服务、在负载均衡里选择一个服务、markServerDown 服务下线、获取服务列表、获取存活的服务器、获取所有服务器(包罗健康和不健康的)
  •  ZoneAwareLoadBalancer:loadBalancer 默认的是 ZoneAwareLoadBalancer 负载均衡器,通过继续父类DynamicServerListLoadBalancer 的 restOfInit 方法,内里比力重要的两个方法,enableAndInitLearnNewServersFeature和updateListOfServers 方法

参考:深入理解Spring Cloud Feign与Ribbon:优雅的微服务调用解决方案_springcloud集成ribbon实现服务列表革新-CSDN博客
Spring Cloud新版本使用LoadBalancer替换Ribbon:探索与实践

在软件开发领域,负载均衡器是一种重要的技术组件,用于实现分布式体系中的流量分发和哀求处理。
随着微服务架构的普及,负载均衡器的选择和使用变得尤为重要。
在Spring Cloud生态体系中,Ribbon和Spring Cloud LoadBalancer是两种常用的客户端负载均衡器。
然而,随着Ribbon的停更,Spring Cloud在Hoxton.M2版本中移除了Ribbon,并引入了Spring Cloud LoadBalancer作为替换品。
本文将介绍LoadBalancer的上风、与Ribbon的差别,以及在实际应用中的使用方法和发起。
一、LoadBalancer的上风
与Ribbon相比,Spring Cloud LoadBalancer具有以下上风:

  • 支持相应式编程:LoadBalancer接纳Spring WebFlux框架实现客户端负载均衡调用,支持相应式编程方式异步访问客户端,能够更好地应对高并发场景。
  • 同一的配置管理:LoadBalancer作为Spring Cloud官方提供的客户端负载均衡器,可以与Spring Cloud其他组件无缝集成,实现同一的配置管理和监控。
  • 更好的可扩展性:LoadBalancer提供了丰富的扩展点,开发者可以根据实际需求自定义负载均衡策略和过滤器,实现更加灵活和可扩展的负载均衡功能。
    二、LoadBalancer与Ribbon的差别
  • 负载均衡算法:Ribbon提供了多种负载均衡算法,如轮询、随机等。而现在LoadBalancer的负载均衡算法相对较少,但将来可能会持续增加。
  • 功能丰富度:Ribbon作为商业化产物,拥有丰富的功能和特性,如超时控制、重试机制等。相比之下,现在LoadBalancer的功能相对较少,但随着其不断发展,将来可能会增加更多功能。
  • 社区支持:Ribbon作为Netflix开源项目,拥有庞大的社区支持和活泼的开发者群体。而现在LoadBalancer的社区相对较小,但随着其广泛应用,相信社区会逐渐强盛。
    三、使用LoadBalancer的发起
  • 评估负载均衡需求:在使用LoadBalancer之前,发起开发者充实评估体系的负载均衡需求,包罗流量分发策略、健康查抄、容错处理等。
  • 自定义负载均衡策略:根据实际需求,可以自定义负载均衡策略和过滤器,实现更加灵活和可扩展的负载均衡功能。例如,可以根据服务调用成功率或相应时间等指标动态调解负载均衡策略。
  • 监控和日志记录:为了更好地相识体系运行状况和问题排查,发起对LoadBalancer进行监控和日志记录。可以使用Spring Cloud的监控组件如Micrometer和Zipkin等来实现对LoadBalancer的性能指标和调用链路的监控。同时,开启LoadBalancer的日志记录功能,以便于问题排查和调试。
  • 兼容性考虑:由于现在LoadBalancer的功能相对较少,因此在某些场景下可能需要考虑与Ribbon或其他负载均衡器的兼容性。假如现有体系已经使用了Ribbon或其他负载均衡器,而且对其功能有较高的依赖性,那么在迁徙到LoadBalancer时需要充实评估和测试体系的兼容性。
    总之,随着Ribbon的停更,Spring Cloud LoadBalancer成为Ribbon的一个可行的替换方案。固然现在其功能和特性相对较少,但随着其不断发展,相信将来会提供更加丰富和灵活的负载均衡功能。在使用LoadBalancer时,发起充实评估体系的负载均衡需求,根据实际需求自定义负载均衡策略和过滤器,并加强监控和日志记录以保障体系的稳固性和可靠性。
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负载均衡策略配置-CSDN博客

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表