ToB企服应用市场:ToB评测及商务社交产业平台

标题: 科普文:微服务之Spring Cloud 客户端负载均衡组件LoadBalancer替换Ribbon [打印本页]

作者: 郭卫东    时间: 2024-10-9 22:05
标题: 科普文:微服务之Spring Cloud 客户端负载均衡组件LoadBalancer替换Ribbon
概叙

负载均衡


负载均衡的两个根本点

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

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

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

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 种内置的负载均衡策略可以选择,这些负载均衡策略如下:
出于性能方面的考虑,我们可以选择用权重策略或地区敏感策略来替换轮询策略,因为这样的实行效率最高。

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是 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从注册中心同步服务列表,然后在客户端通过配置的负载均衡策略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还提供:

Ribbon核心组件

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

参考:深入理解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具有以下上风:
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企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4