热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

《SpringCloud》学习(二)负载均衡!

第二章负载均衡负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。SpringCloudRibbon是一个基于HTTP和TCP的客户端负载均衡工具,

第二章 负载均衡


  负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。Spring Cloud Ribbon是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于Netflix Ribbon实现,通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模板请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon几乎存在于每一个Spring Cloud 构建的微服务和基础设施中。因为微服务间的调用,API 网关的请求转发等内容实际上都是通过Ribbon来实现的

  通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:

  -服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。
  -服务消费者直接通过调用被@LoadBalanced 注解修饰过的 RestTemplate 来实现面向服务的接口调用。


  这样,我们就可以将服务提供者的高可用以及服务消费者的负载均衡调用一起实现了。但是RestTemplate是Spring提供。跟Ribbon的客户端负载均衡又有什么关系,又是如何实现?下文详解。

 

一.LoadBalancerClent 和 RibbonLoadBalancerClient

 

  1.LoadBalancerClent 

  通过@LoadBalanced注解源码的注释中可以知道,该注解用来给RestTemplate做标记,以使用负载均衡的客户端(LoadBalancerClent)来配置它。下图贴出了LoadBalancerClent源码。

  

  1.1 Servicelnstance choose (String serviceid)根据传入的服务名serviceld, 从负载均衡器中挑选一个对应服务的实例。
  1.2 T execute (String serviceid, LoadBalancerRequest request)使用从负载均衡器中挑选出的服务实例来执行请求内容。
  1.3 URI reconstructURI(Serviceinstance instance , URI original )为系统构建 一个合适的host:port形式的URI。

  从方法名的诠释相信大家已经看出一些倪端,但是并不是大家想的那样(先调用choose挑选服务,再组成URI,最后调用execute执行请求)。因为本人这里这里踩过坑,先强调下!

  重要的是execute方法。

  2.RibbonLoadBalancerClient

  RibbonLoadBalancerClient是LoadBalancerClent的实现类。要点是它实现了父类的execute方法。贴出execute的方法实现。

  

  可以看出进入方法就调用自身的getServer方法获取服务,继续。

  

  IloadBalancer.chooseServer方法解释:通过某种策略,从负载均衡器中挑选出个具体的服务实例,也就是这里去真正的去挑选我们调用的服务实例。但是IloadBalancer是一个接口,默认注入的是它的子类实现ZoneAwareLoadBalancer。也就是挑选服务的任务交给了ZoneAwareLoadBalancer。

  至于如何如挑选,在第四节负载均衡策略会详解。

  

二.LoadBalancerAutoConfiguration负载均衡地自动化配置类

  LoadBalancerAutoConfiguration为实现客户端负载均衡地自动化配置类。由于类源码稍长,就不贴了,我下图写出该类主要描述。

  

 

  1.被@ConditionalOnClass(RestTemplate.class)和@ConditionalOnBean(LoadBalancerClent.class)修饰表示在当前工程中必须有RestTemplate的Bean和LoadBalancerCliet的实现 Bean,理所当然嘛。

  2.创建了一个LoadBalancerInerceptor的Bean,用于实现对客户端发起请求时进行拦截, 以实现客户端负载均衡。这里贴出了LoadBalancerInerceptor的源码,我们可以看到在拦截器中注入了 LoadBalancerClient的实现,其实就是上文提到的RibbonLoadBalancerClient类!

   

 

  3.创建了一个RestTemplateCustomizer的Bean, 用于给RestTemplate增加LoadBalancerInterceptor拦截器。
  4.维护了一个被@LoadBalanced 注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerinInerceptor拦截器。

  我们暂且可以推出:当一个被@LoadBalanced注解修饰的RestTemplate对象向外发起HTTP请求时,会LoadBalancerinterceptor类的intercept函数所拦截,然后调用RibbonLoadBalancerClient类的execute函数。继续向下看!

三.ZoneAwareLoadBalancer负载均衡器

   

  我们已经知道ZoneAwareLoadBalancer是ILoadBalancer的实现类,并且ZoneAwareLoadBalancer.chooseServer方法是挑选出个具体的服务实例。但是ILoadBalancer和ZoneAwareLoadBalancer并不是直接实现关系,他们有多层实现继承关系,如下图。

  

  他们对ILoadBalancer一层层的实现扩展构成了ZoneAwareLoadBalancer,这里对他们具体如何实现扩展不做描述,大家有兴趣的可以去了解下!

  ZoneAwareLoadBalancer中要点:

  1.定义了负载均衡的处理规则IRule对象,负载均衡器实际将服务实例选择任务又委托给了IRule 实例中的choose函数来实现。而在这里,默认初始化了 RoundRobinRule为IRule的实现对象。RoundRobinRule 实现了最基本且常用的线性负载均衡规则(轮询),换而言之就是IRule的实现类就是定义不同的服务选择规则,比如轮询,随机,权重等等

 

  2.实现了服务实例清单在运行期的动态更新能力。同时它还具备了对服务实例清单的过滤功能:我们可以通过过滤器来选择性地获取一批服务实例清单。它定义了两个抽象方法:getInitialListOfServers用于获取初始化的服务实例清单, 而getUpdatedListOfServers用于获取更新的服务实例清单。

  在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端的清单来自于服务注册中心,如上一章我们介绍的Eureka服务端。在客户端负载均衡中也需要心跳去维护服务端清单的健康性,只是这个步骤需要与服务注册中心配合完成。

  当Ribbon与Eureka联合使用时,Ribbon的服务实例清单RibbonServerList会被DiscoveryEnabledNIWSServerList重写,扩展成从Eureka注册中心中获取服务端列表。目的是为了对服务清单进行负载均衡需要的封装处理。利用Eureka的事件监听器来驱动服务列表的更新操作。它先创建了一个Runnable的线程实现,在该实现中调用了更新服务实例列表的方法, 最后再为这个Runnable线程实现启动了一个定时任务(默认30秒)来执行。

  简而言之ZoneAwareLoadBalancer的职责就是获取到服务清单,让IRole以某种规则选取!

 

  到这里我们就可以先整理下一个简单的负载均衡的流程:

  负载均衡流程&#xff1a;当一个被&#64;LoadBalanced注解修饰的RestTemplate对象向外发起HTTP请求时&#xff0c;会被LoadBalancerinterceptor类的intercept函数所拦截。由于我们在使用RestTemplate时采用了服务名作为host&#xff0c;所以直接从 HttpRequest的URI对象中通过 getHost()就可以拿到服务名&#xff0c;然后调用RibbonLoadBalancerClient类的execute函数&#xff0c;函数中ZoneAwareLoadBalancer的 chooseServer函数通过某种规则获取了负载均衡策略分配到的服务实例对象Server&#xff08;实质此任务委托给IRule的实现类RoundRobinRule<默认轮询>实例中的choose函数来实现&#xff09;&#xff0c;再将获取服务将其内容包装成RibbonServer对象&#xff0c;然后使用该对象再回调 LoadBalancerinterceptor请求拦截器中LoadBalancerRequest的apply(final ServiceInstance instance) 函数&#xff0c;向一个实际的具体服务实例发起请求&#xff0c;因为服务实例有ip,端口等元数据&#xff0c;从而实现一开始以服务名为host的URI请求到 host:post形式的实际访问地址的转换。

 

四.IRule负载均衡策略

   我们已经知道了IRule的实现类即是负载均衡规则&#xff0c;通过注入不同实现类来设定不同的选取策略。我们来看看它的一些常用实现类。

  1. RandomRule&#xff1a;该策略实现了从服务实例清单中随机选择一个服务实例的功能。具体是通过rand.nextint(serverCount&#xff09;函数来获取一个最大为服务数量的随机Int变量&#xff0c;在服务列表通过索引值来返回具体实例。

 

  2. RoundRobinRule&#xff1a;该策略实现了按照线性轮询的方式依次选择每个服务实例的功能。循环条件内&#xff0c;为服务增加了一个count计数变量&#xff0c;该变量会在每次循环之后累加&#xff08;线性轮询的实现则是通过Atomicinteger nextServerCyclicCounter对象实现&#xff0c;每次进行实例选择时通过调用 incrementAndGetModulo函数实现递增&#xff09;。

 

  3. RetryRule&#xff1a;该策略实现了一个具备重试机制的实例选择功能。默认使用了 RoundRobinRule实例。而在choose方法中则实现了对内部定义的策略进行反复尝试的策略&#xff0c;若期间能够选择到具体的服务实例就返回&#xff0c;若一段时间&#xff08;可设置&#xff09;选择不到就根据设置的尝试结束返回 null。

 

  4. WeightedResponseTimeRule&#xff1a;该策略是对RoundRobinRule 的扩展&#xff0c;增加了根据实例的运行情况来计算权重&#xff0c;并根据权重来挑选实例&#xff0c;以达到更优的分配效果。会创建定时任务&#xff08;默认30秒&#xff09;用来为每个服务实例计算权重。权重机制其实是为每个服务生成权重区间&#xff0c;比如根据响应时间为三个服务生成了权重区间&#xff1a;实例A: [0, 100]   实例B: ( 100,150]   实例C: (150,300&#xff09; &#xff08;权重计算这里不做描述&#xff09;。然后会生成一个[0, 最大权重值&#xff09;区间内的随机数。查看随机数在那个区间&#xff0c;就拿到某个服务实例

 

  5. BestAvailableRule&#xff1a;该策略在实现中它注入了负载同时在具体的 choose 算法中利用保存的实例统计信息来选择满足要求的实例。通过遍历负载均衡器中维护的所有服务实例&#xff0c;会过滤掉故障的实例&#xff0c;并找出并发请求数最小的一个&#xff0c;所以该策略的特性是可选出最空闲的实例。

 

  6. PredicateBasedRule&#xff1a;这是一个基于 Predicate 实现的策略&#xff0c; Predicate是对集合进行过滤的条件接口。在choose函数中&#xff0c;先通过子类中实现的 Predicate 逻辑来过滤一部分服务实例&#xff0c;然后再以线性轮询的方式从过滤后的实例清单中选出一个。

 

  之前已经知道负载均衡流程&#xff0c;本节也介绍了常用的负载均衡策略&#xff0c;Spring Cloud负载均衡已经有了一定了解。本文也省略了一些内容比如过滤器工作机制&#xff0c;组装host:port的URI,如何封装负载均衡所需的服务清单等等&#xff0c;有机会的话我会单独介绍下&#xff01;

  


 

本文链接&#xff1a;《Spring Cloud》学习&#xff08;二&#xff09; 负载均衡&#xff01;
转载声明&#xff1a;本博客由静影残月创作。可自由转载、引用&#xff0c;但需署名作者且注明文章出处。

转:https://www.cnblogs.com/crazycheng/p/10826294.html



推荐阅读
  • Spring Cloud Config 使用 Vault 作为配置存储
    本文探讨了如何在Spring Cloud Config中集成HashiCorp Vault作为配置存储解决方案,基于Spring Cloud Hoxton.RELEASE及Spring Boot 2.2.1.RELEASE版本。文章还提供了详细的配置示例和实践建议。 ... [详细]
  • 本文介绍如何使用 Angular 6 的 HttpClient 模块来获取 HTTP 响应头,包括代码示例和常见问题的解决方案。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 我有一个SpringRestController,它处理API调用的版本1。继承在SpringRestControllerpackagerest.v1;RestCon ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 本文详细介绍了如何在 Android 中使用值动画(ValueAnimator)来动态调整 ImageView 的高度,并探讨了相关的关键属性和方法,包括图片填充后的高度、原始图片高度、动画变化因子以及布局重置等。 ... [详细]
  • springMVC JRS303验证 ... [详细]
  • 烤鸭|本文_Spring之Bean的生命周期详解
    烤鸭|本文_Spring之Bean的生命周期详解 ... [详细]
  • 深入解析Spring Cloud微服务架构与分布式系统实战
    本文详细介绍了Spring Cloud在微服务架构和分布式系统中的应用,结合实际案例和最新技术,帮助读者全面掌握微服务的实现与优化。 ... [详细]
  • 本文详细探讨了在微服务架构中,使用Feign进行远程调用时出现的请求头丢失问题,并提供了具体的解决方案。重点讨论了单线程和异步调用两种场景下的处理方法。 ... [详细]
  • Spring Cloud学习指南:深入理解微服务架构
    本文介绍了微服务架构的基本概念及其在Spring Cloud中的实现。讨论了微服务架构的主要优势,如简化开发和维护、快速启动、灵活的技术栈选择以及按需扩展的能力。同时,也探讨了微服务架构面临的挑战,包括较高的运维要求、分布式系统的复杂性、接口调整的成本等问题。最后,文章提出了实施微服务时应遵循的设计原则。 ... [详细]
  • 前言无论是对于刚入行工作还是已经工作几年的java开发者来说,面试求职始终是你需要直面的一件事情。首先梳理自己的知识体系,针对性准备,会有事半功倍的效果。我们往往会把重点放在技术上 ... [详细]
  • 字节跳动夏季招聘面试经验分享
    本文详细记录了字节跳动夏季招聘的面试经历,涵盖了一、二、三轮面试的技术问题及项目讨论,旨在为准备类似面试的求职者提供参考。 ... [详细]
  • 利用YAML配置Resilience4J的Circuit Breaker
    本文探讨了Resilience4j作为现代Java应用程序中不可或缺的容错工具,特别介绍了如何通过YAML文件配置Circuit Breaker以提高服务的弹性和稳定性。 ... [详细]
author-avatar
郑云雪
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有