Spring Cloud LoadBalancer 负载均衡策略与缓存机制

这篇具有很好参考价值的文章主要介绍了Spring Cloud LoadBalancer 负载均衡策略与缓存机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. 什么是 LoadBalancer ?

2. 负载均衡策略的分类

2.1 常见的负载均衡策略

3. 为什么要学习 Spring Cloud Balancer ?

4. Spring Cloud LoadBalancer 内置的两种负载均衡策略

4.1 轮询负载均衡策略(默认的)

4.2 随机负载均衡策略

4.2.1 创建随机负载均衡策略

 4.2.2 设置随机负载均衡策略

5. Nacos 权重负载均衡器

5.1 创建 Nacos 负载均衡器

5.2 设置 Nacos 负载均衡器

6. 自定义负载均衡器

6.1 创建自定义负载均衡器

6.2 封装自定义负载均衡器

6.3 为服务设置自定义负载均衡策器

7.  Spring Cloud LoadBalancer 中的缓存机制

7.1 Spring Cloud LoadBalancer 中缓存机制的一些特性

7.2 关闭缓存


1. 什么是 LoadBalancer ?

LoadBalancer(负载均衡器)是一种用来分发网络或应用程序流量到多个服务器的技术。它可以防止任何单一服务的过载,通过分散负载来保持整个系统的平稳运行,保证系统的高可用性和可靠性。

2. 负载均衡策略的分类

负载均衡策略大体上分为两类:服务端的负载均衡和客户端的负载均衡

① 服务端负载均衡 (如 Nginx、F5)

请求先到达一个中介(如负载均衡器设备或者服务,例如Nginx),由这个中介根据配置的策略将请求分发到后端的多个服务器中。它对客户端是透明的,即客户端不需要知道有多少服务器以及它们的存在

2020.0.1 loadbalancer的缓存设置,springcloud,spring cloud,spring,后端

② 客户端负载均衡 (如 Ribbon、Spring Cloud LoadBalancer)

请求的分配逻辑由客户端持有,客户端直接决定将请求发送到哪一个服务器。也就是说在客户端负载均衡中,客户端通常具备一份服务列表,它知道每个服务的健康状况,基于这些信息和负载均衡策略,客户端会选择一个最适合的服务去发送请求。

2020.0.1 loadbalancer的缓存设置,springcloud,spring cloud,spring,后端

服务端负载均衡和客户端负载均衡策略有什么区别 ?

它俩的区别主要在灵活性和性能两方面(结合上面两幅图来理解):

1. 灵活性

  • 客户端负载均衡更加灵活,它可以针对每一个请求,每一个 service 做单独的负载均衡配置。

2. 性能

  • 客户端负载均衡性能相对来说更好一点,因为服务端负载均衡中,当请求来了之后,它得先去到服务端的负载均衡,然后服务端的负载均衡再将请求发送给对应的服务器,整个过程发送了两次请求,而客户端负载均衡只需要发送一次请求。
  • 其次,服务端负载均衡中,客户端的请求都先打到了中心节点上,这个流量是很大的,所以服务端的负载均衡器,它的压力相对来说就比较大,那么性能就不可能比客户端负载均衡高。
  • 反观客户端负载均衡,它就没有所谓的中心节点,它将集中的压力给释放了,因为客户端有成千上万个,它可以让每个客户端去调用自己的负载均衡器,而不是让成千上万个客户端去调用一个负载均衡器。

【扩充知识】 

如果将负载均衡器视为代理,那么服务端负载均衡可以视作是反向代理的一种形式,因为它接收客户端请求后再决定将其分配给哪一个服务器;而客户端负载均衡则可以看作具有正向代理的性质,因为客户端知道要联系的服务列表,并直接向选定的服务器发送请求。

  • 正向代理:正向代理类似于一个中间人,代表客户端去请求服务。客户端必须要配置代理,因此客户端是知道代理的存在的。正向代理隐藏了客户端的信息,服务器不知道真正的请求者是谁。

  • 反向代理:反向代理则是代表服务器接收客户端的请求。客户端通常不知道后面有多少服务器,也不需要知道。反向代理隐藏了服务端的信息,客户端只与反向代理交互,像Nginx这样的服务器就是一个反向代理的例子。

2.1 常见的负载均衡策略

常见的负载均衡策略有以下几种:

  1. 轮询:按顺序分配,每个服务器轮流接收一个连接。
  2. 随机选择:随机挑选服务器,分散负载。
  3. 最少连接:选择当前连接数最少的服务器。
  4. IP哈希:根据用户IP分配,相同IP的请求总是发给同一服务器。
  5. 加权轮询:类似轮询,但服务器根据权重获取更多或更少请求。
  6. 加权随机选择:权重高的服务器有更高几率被选中。
  7. 最短响应时间:响应时间短的服务器优先接收新请求。

3. 为什么要学习 Spring Cloud Balancer ?

因为 Ribbon 作为早期的客户端负载均衡工具,在 Spring Cloud 2020.0.0 版本之后已经被移除了,取而代之的是 Spring Cloud LoadBalancer,而且 Ribbon 也已经不再维护,所以它也是 Spring 官方推荐的负载均衡解决方案。

其他一些原因:

  1. 更好的兼容性:LoadBalancer就像一个全新的配件,它与Spring Cloud的其他组件搭配得更好。

  2. 支持响应式编程:现在编程界有一种新的编程方式叫做“响应式编程”,LoadBalancer能很好地支持这种现代编程风格。

  3. 易于使用和维护:LoadBalancer的设计易于拼装和修改,这对于开发者来说,维护和定制起来更加方便。

  4. 多功能:LoadBalancer有很多内置功能,比如自动帮你挑选服务器,就像购物网站帮你推荐商品一样聪明。

4. Spring Cloud LoadBalancer 内置的两种负载均衡策略

4.1 轮询负载均衡策略(默认的)

从它的源码实现可以看出来默认的负载均衡策略是轮询的策略。

IDEA 搜索它的配置类 LoadBalancerClientConfiguration:

2020.0.1 loadbalancer的缓存设置,springcloud,spring cloud,spring,后端

进入到 RoundRobinLoadBalancer 这个类里边,定位到 getInstanceResponse 方法,就能看到轮询策略的关键代码:

private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
    if (instances.isEmpty()) {
        if (log.isWarnEnabled()) {
            log.warn("No servers available for service: " + this.serviceId);
        }

        return new EmptyResponse();
    } else if (instances.size() == 1) {
        return new DefaultResponse((ServiceInstance)instances.get(0));
    } else {
        // 轮询策略的关键代码
        int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
        ServiceInstance instance = (ServiceInstance)instances.get(pos % instances.size());
        return new DefaultResponse(instance);
    }
}

理解关键代码:

int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
  • this.position.incrementAndGet() 方法等价于 "++随机数 "。这是一个原子操作,保证了每次调用都会得到一个唯一的递增数值。
  • & Integer.MAX_VALUE 这部分是一个位运算,它确保了如果 position 的值增加到超过 Integer.MAX_VALUE 时,不会产生负数。其一,在轮询算法中,如果计数器变成负数,那么取余操作可能会产生负的索引值,这是无效的; 其二,也可也保证在相同规则底下的公平性。
ServiceInstance instance = (ServiceInstance)
                instances.get(pos % instances.size()); // 进行轮询选择
  • instances 是一个包含所有服务实例的列表。
  • pos % instances.size() 计算的是 pos 除以 instances 列表大小的余数,这保证了不论 pos 增长到多大,这个表达式的结果都是在 0instances.size() - 1 的范围内,这样就可以循环地从服务实例列表中选择服务实例。

4.2 随机负载均衡策略

实现随机负载均衡策略的步骤:

① 创建随机负载均衡策略

② 设置随机负载均衡策略

接下来的操作都是基于这篇博客基础上去操作的,有需要的可以先去看看这篇博客,先把前置的代码准备好:https://blog.csdn.net/xaiobit_hl/article/details/134142521

4.2.1 创建随机负载均衡策略

这些写法都是相通的,可以仿照源码中的轮询策略的关键代码:

可以去源码中的LoadBalancerClientConfiguration中去定位到 reactorServiceInstanceLoadBalancer 方法,然后复制下来,修改几个关键地方即可。

public class RandomLoadBalancerConfig {

    // 随机的负载均衡策略
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty("loadbalancer.client.name");
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name,
                        ServiceInstanceListSupplier.class), name);
    }
}

 4.2.2 设置随机负载均衡策略

在 consumer 模块中的 service 接口上设置负载均衡策略:

@Service
@FeignClient("loadbalancer-service")
// 设置局部的负载均衡策略
@LoadBalancerClient(name = "loadbalancer-service",
    configuration = RandomLoadBalancerConfig.class)
public interface UserService {

    @RequestMapping("/user/getname")
    public String getName(@RequestParam("id") Integer id);
}

PS:有时候局部的负载均衡策略不会生效(版本问题),可以将其设为全局的负载均衡策略。

如何设置全局的负载均衡策略:(在启动类上加 @LoadBalancerClients 注解)

@SpringBootApplication
@EnableFeignClients  // 开启 OpenFeign
// 设置全局的负载均衡策略
@LoadBalancerClients(defaultConfiguration =
    RandomLoadBalancerConfig.class)
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

}

这个时候,就是随机的负载均衡策略了,可以启动两个生产者和消费者,然后拿着消费者这边的端口去获取服务感受。

5. Nacos 权重负载均衡器

Nacos 中有两种负载均衡策略:权重负载均衡策略和 CMDB(地域就近访问)标签负载均衡策略

它默认的策略是权重。

在 Spring Cloud Balancer 配置为 Nacos 负载均衡器的步骤:

① 创建 Nacos 负载均衡器

② 设置 Nacos 负载均衡器

5.1 创建 Nacos 负载均衡器

配置 Nacos 负载均衡需要注入 NacosDiscoveryProperties 这个类,因为它需要使用到配置文件中的一些关键信息。

@LoadBalancerClients(defaultConfiguration = NacosLoadBalancerConfig.class)
public class NacosLoadBalancerConfig {
    @Resource
    NacosDiscoveryProperties nacosDiscoveryProperties;

    @Bean
    public ReactorLoadBalancer<ServiceInstance> nacosLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty("loadbalancer.client.name");
        return new NacosLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name,
                        ServiceInstanceListSupplier.class), name, nacosDiscoveryProperties);
    }
}

5.2 设置 Nacos 负载均衡器

@Service
@FeignClient("loadbalancer-service")
// 设置局部的负载均衡策略
@LoadBalancerClient(name = "loadbalancer-service",
    configuration = NacosLoadBalancerConfig.class)
public interface UserService {

    @RequestMapping("/user/getname")
    public String getName(@RequestParam("id") Integer id);
}

再测试之前,可以先将 Nacos 中一个生产者的权重给设置为 10,一个设置为 1,这样就能明显感受到 Nacos 权重的负载均衡策略了。

2020.0.1 loadbalancer的缓存设置,springcloud,spring cloud,spring,后端

6. 自定义负载均衡器

自定义负载均衡策略需要 3 个步骤:

① 创建自定义负载均衡器

② 封装自定义负载均衡器

③ 为服务设置自定义负载均衡策器

6.1 创建自定义负载均衡器

这里也是可以参考源码的实现的,搜索 RandomLoadBalancer 这个类,模仿它的实现去创建自定义负载均衡器。

Ⅰ. 创建一个负载均衡类, 并让其实现 ReactorServiceInstanceLoadBalancer 接口;

Ⅱ. 复制 RandomLoadBalancer 的整个方法体,粘贴到自定义负载均衡类中,并修改构造方法名称

Ⅲ. 在关键方法 getInstanceResponse 中实现自定义负载均衡策略(以IP哈希负载均衡为例)

public class CustomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(CustomLoadBalancer.class);
    private final String serviceId;
    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public CustomLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = (ServiceInstanceListSupplier)this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map((serviceInstances) -> {
            return this.processInstanceResponse(supplier, serviceInstances);
        });
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier, List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = this.getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback)supplier).selectedServiceInstance((ServiceInstance)serviceInstanceResponse.getServer());
        }

        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + this.serviceId);
            }

            return new EmptyResponse();
        } else {
            // 自定义负载均衡策略
            
            // 获取 Request 对象
            ServletRequestAttributes attributes = (ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String ipAddress = request.getRemoteAddr();
            System.out.println("用户 IP:" + ipAddress);
            int hash = ipAddress.hashCode();
            // IP 哈希负载均衡【关键代码】
            int index = hash % instances.size();
            // 得到服务实例的方法
            ServiceInstance instance = (ServiceInstance) instances.get(index);
            return new DefaultResponse(instance);
        }
    }
}

6.2 封装自定义负载均衡器

public class CustomLoadBalancerConfig {
    // IP 哈希负载均衡
    @Bean
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty("loadbalancer.client.name");
        return new CustomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name,
                        ServiceInstanceListSupplier.class), name);
    }
}

6.3 为服务设置自定义负载均衡策器

@Service
@FeignClient("loadbalancer-service")
// 设置局部的负载均衡策略
@LoadBalancerClient(name = "loadbalancer-service",
    configuration = CustomLoadBalancerConfig.class)
public interface UserService {

    @RequestMapping("/user/getname")
    public String getName(@RequestParam("id") Integer id);
}

 PS:测试的时候发现自定义的负载均衡策略不生效怎么办 ?

① 把前边的 Nacos 的负载均衡器一整个注释掉(包括 @LoadBalancerClients注解),只提供一个类。

2020.0.1 loadbalancer的缓存设置,springcloud,spring cloud,spring,后端

② 如果设置局部的负载均衡不生效,就去启动类上设置全局的负载均衡策略。

@SpringBootApplication
@EnableFeignClients  // 开启 OpenFeign
// 设置全局的负载均衡策略
@LoadBalancerClients(defaultConfiguration =
    CustomLoadBalancerConfig.class)
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

}

7.  Spring Cloud LoadBalancer 中的缓存机制

Spring Cloud LoadBalancer 中获取服务实例有两种方式:

1. 实时获取:每次都从注册中心得到最新的健康实例(效果好,开销大)

2. 缓存服务列表:每次得到服务列表之后,缓存一段时间(既保证性能,也能保证一定的及时性)

Spring Cloud LoadBalancer 默认开启了缓存服务列表的功能。

测试 Spring Cloud LoadBalancer 的缓存机制:

1. 将前面设置负载均衡策略全部注释掉,使用默认的轮询测试(便于观察)

2. 准备两个服务

3. 将其中一个服务下线,下线的同时立马去获取服务,然后等大约 35s ,再去获取服务

2020.0.1 loadbalancer的缓存设置,springcloud,spring cloud,spring,后端

【测试结果】 当我下线第一个服务的时候,立马去获取服务,这个时候还是两个服务轮询的获取,等过了 35s 左右,就只能获取到 64067 这个服务了。

7.1 Spring Cloud LoadBalancer 中缓存机制的一些特性

默认特性如下:

① 缓存的过期时间为 35s;

② 缓存保存个数为 256 个。

我们可以通过在配置文件中去设置这些特性:

spring:
  cloud:
    loadbalancer:
      cache:
        ttl: 35s  # 过期时间
        capacity: 1024  # 设置缓存个数

7.2 关闭缓存

关闭 Spring Cloud LoadBalancer 中的缓存可以通过以下配置文件来设置:

spring:
  cloud:
    loadbalancer:
      cache:
        enabled: false  # 关闭缓存

PS:尽管关闭缓存对于开发和测试很有用,但是在生产环境上,它的效率是要远低于开启缓存,所以在生产环境上始终都要开启缓存。文章来源地址https://www.toymoban.com/news/detail-812863.html

到了这里,关于Spring Cloud LoadBalancer 负载均衡策略与缓存机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring Cloud】Ribbon 实现负载均衡的原理,策略以及饥饿加载

    在前文《深入理解 Eureka 注册中心的原理、服务的注册与发现》中,介绍了如何使用 Eureka 实现服务的注册与拉取,并且通过添加 @LoadBalanced 注解实现了负载均衡。这种自动化的背后隐藏着许多疑问: 服务是在何时进行拉取的? 负载均衡是如何实现的? 负载均衡的原理和策略

    2024年02月07日
    浏览(47)
  • 【springcloud 微服务】Spring Cloud Ribbon 负载均衡使用策略详解

    目录 一、前言 二、什么是Ribbon 2.1 ribbon简介 2.1.1  ribbon在负载均衡中的角色

    2024年02月02日
    浏览(64)
  • 【Spring Cloud】深入探索 Nacos 注册中心的原理,服务的注册与发现,服务分层模型,负载均衡策略,微服务的权重设置,环境隔离

    在微服务架构中,服务注册中心是整个体系中的关键组件之一。它负责服务的注册、发现和管理,为微服务之间的通信提供了基础设施。在这方面,Nacos(Namespace Aware Clustered Object Storage)作为一种服务发现和配置管理系统,提供了丰富的功能,旨在简化微服务架构中的服务注

    2024年02月06日
    浏览(214)
  • springCloud-LoadBalancer负载均衡微服务负载均衡器LoadBalancer

    2020年前SpringCloud是采用Ribbon作为负载均衡实现,但是在2020后采用了LoadBalancer替代 1.RandomLoadBalancer-随机分配策略 2.RoundRobinLoadBalancer-轮询分配策略(默认)

    2024年04月15日
    浏览(55)
  • Spring Cloud Ribbon:负载均衡

    1. 介绍 Spring Cloud Ribbon 1.1 什么是 Spring Cloud Ribbon Spring Cloud Ribbon是Netflix开源的负载均衡器,它为分布式服务提供了客户端负载均衡的功能。Ribbon可以根据一系列的负载均衡算法和配置策略,将客户端的请求动态分发到多个服务实例上,以实现高可用性和性能优化。 1.2 负载均

    2024年02月19日
    浏览(43)
  • 【Spring Cloud 四】Ribbon负载均衡

    【Spring Cloud一】微服务基本知识 【Spring Cloud 三】Eureka服务注册与服务发现 目前公司项目使用的注册中心主要是Spring Cloud Alibaba的Nacos做的注册中心和配置中心。并且Nacos使用了Ribbon作为默认的负载均衡器。但是相当于将Ribbon的负载均衡给透明化了,日常开发明面上是看不到

    2024年02月14日
    浏览(50)
  • 聊聊spring-cloud的负载均衡

    在微服务架构中,负载均衡是非常重要的一个环节,可以有效地提高系统的可用性和稳定性。在Spring Cloud中,提供了多种负载均衡组件和算法,本文将详细介绍如何减少负载均衡对系统性能的影响。 在选择负载均衡算法时,需要根据实际情况进行选择。常用的负载均衡算法有

    2024年02月16日
    浏览(32)
  • Spring cloud负载均衡 @LoadBalanced注解原理

    接上一篇文章,案例代码也在上一篇文章的基础上。 在上一篇文章的案例中,我们创建了作为Eureka server的Eureka注册中心服务、作为Eureka client的userservice、orderservice。 orderservice引入RestTemplate,加入了@LoadBalanced注解,代码如下: 从而,我们实现了基于Eureka注册中心的微服务治

    2024年02月05日
    浏览(48)
  • 负载均衡 LoadBalancer

    负载均衡 负载均衡一般分为 服务端负载均衡 和 客户端负载均衡 服务端负载均衡: 指在服务器端进行负载均衡的策略。在这种策略下,负载均衡器位于服务器端(如 Nginx),当客户端发起服务调用时,根据服务器的负载情况,将请求分发到不同的服务器上,以实现请求的均

    2024年01月17日
    浏览(59)
  • Spring Cloud中的服务路由与负载均衡

    本文将讨论Spring Cloud中的服务路由问题,包括服务发现、服务注册、服务消费、服务提供以及服务路由实现。 在微服务架构中往往需要根据服务名来调用服务。此时服务发现就变得非常重要。在Spring Cloud中可以通过在 pom.xml 文件中引入 spring-cloud-starter-netflix-eureka-server 依赖来

    2024年02月06日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包