【云原生&微服务三】SpringCloud之Ribbon是这样实现负载均衡的(源码剖析@LoadBalanced原理)

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: 【云原生&微服务三】SpringCloud之Ribbon是这样实现负载均衡的(源码剖析@LoadBalanced原理)

@[toc]

一、前言

在前面的文章,博主聊了Ribbon如何与SpringCloud、Eureka集成,Ribbon如何自定义负载均衡策略:

  1. 【云原生&微服务一】SpringCloud之Ribbon实现负载均衡详细案例(集成Eureka、Ribbon)
  2. 【云原生&微服务二】SpringCloud之Ribbon自定义负载均衡策略(含Ribbon核心API)

前面我们学会了怎么使用Ribbon,那么为什么给RestTemplate类上加上了@LoadBalanced注解就可以使用Ribbon的负载均衡?SpringCloud是如何集成Ribbon的?Ribbon如何作用到RestTemplate上的?如何获取到的ILoadBalancer?

本文就这几个问题展开讨论。

PS: 文章中涉及到的SpringBoot相关知识点,比如自动装配,移步博主的SpringBoot专栏:Spring Boot系列

PS2:Ribbon依赖Spring Cloud版本信息如下:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.3.7.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--整合spring cloud-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR8</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--整合spring cloud alibaba-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.5.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

==下面以请求http://localhost:9090/say/saint为入口进行debug。==

二、@LoadBalanced注解原理

这里我们就来看看为什么采用@Bean方法将RestTemplate注入到Spring容器时,加上@LoadBalanced注解就可以实现负载均衡?
在这里插入图片描述

1、找找@LoadBalanced注解在哪

在这里插入图片描述
在这里插入图片描述
@LoadBalanced在org.springframework.cloud.client.loadbalancer包下,属于spring-cloud-commons项目;

嗯,然后呢?既然是SpringCloud项目,二话不说开找自动装配类XXXAutoConfiguration 或 配置类XXXConfiguration。

上面说了@LoadBalanced属于spring-cloud-commons项目,找到其jar包下/META-INF/spring.factories文件(为啥找这个文件呢,见SpringBoot自动装配机制原理):
在这里插入图片描述
既然是负载均衡,我们从类的命名来推测,锁定AsyncLoadBalancerAutoConfiguration类和LoadBalancerAutoConfiguration类;这两个类选哪个呢,“小公鸡点到谁就是谁”?还是看命名,AsyncLoadBalancerAutoConfiguration中有Async,是异步负载均衡请求的;我们看同步,同步好debug,进一步锁定到LoadBalancerAutoConfiguration类。

1)@LoadBalanced流程图总述

在这里插入图片描述

2)LoadBalancerAutoConfiguration自动装配类

在这里插入图片描述
进到类里,我们发现它组合了一个RestTemplate集合,即:我们创建的那个RestTemplate实例(被@LoadBalanced注解标注)会放到这里来!

  • 此处细节涉及到SpringBoot的源码,为了避免偏题,本文仅提供一种思路,不做详细解释;

在LoadBalancerAutoConfiguration类中会注入一个SmartInitializingSingleton实例;
在这里插入图片描述SmartInitializingSingleton接口中只有一个afterSingletonsInstantiated()方法;在SpringBoot启动过程中,当RestTemplate实例化完之后,会执行这个方法,做如下操作:

  1. 遍历每个RestTemplate实例,然后再遍历所有的RestTemplateCustomizer对每个RestTemplate实例做定制化操作,即添加拦截器LoadBalancerInterceptor操作。

1> RestTemplateCustomizer从哪里来的?

还是在LoadBalancerAutoConfiguration类中会通过@Bean方法注入RestTemplateCustomizer
在这里插入图片描述

2> LoadBalancerInterceptor拦截器

RestTemplateCustomizer所做的定制化就是给RestTemplate添加一个LoadBalancerInterceptor 拦截器;LoadBalancerInterceptorRestTemplateCustomizer都在LoadBalancerAutoConfiguration的静态内部类LoadBalancerInterceptorConfig中,在SpringBoot启动流程中我们知道,同一个类中@Bean方法的加载是从上至下的,所以肯定是LoadBalancerInterceptor先加载到Spring容器中。

此外,LoadBalancerAutoConfiguration类中还会自动装配一些Retry....相关的类,用于请求重试。

看到这,我们知道了Ribbon如何作用到RestTemplate上!但是好像还差一点东西,我要通过RestTemplate做一个操作时,入口在哪?

2、RestTemplate执行请求时的入口

上面我们说到,针对每一个RestTemplate,都会给其添加一个LoadBalancerInterceptor拦截器,所以我们对RestTemplate执行某个操作时,会被LoadBalancerInterceptor所拦截。
在这里插入图片描述
在这里插入图片描述LoadBalancerInterceptor中组合了LoadBalancerClient,通过LoadBalancerClient做负载均衡;

然而想要将LoadBalancerInterceptor注入到Spring容器,需要先将LoadBalancerClient注入到Spring容器。那么LoadBalancerClient是何时注入的?

1)LoadBalancerClient何时注入到Spring容器

去哪找?我去哪找?既然我们集成了netflix-ribbon,找一下以netflix-ribbon命名的jar包;找到spring-cloud-netflix-ribbonjar包;老规矩,SpringClout项目直接就开找自动装配类XxxAutoConfiguration,自动装配类找不到注入Bean,再找配置类XxxConfiguration。
在这里插入图片描述

找到RibbonAutoConfiguration类,其中会注入LoadBalancerClient

在这里插入图片描述
注意@AutoConfigureAfter注解和@AutoConfigureBefore注解,其表示:RibbonAutoConfiguration类加载要发生在LoadBalancerAutoConfiguration类加载之前、发生在EurekaClientAutoConfiguration类加载之后。

到这里,LoadBalancerClient实例比定在LoadBalancerAutoConfiguration加载之前已经注入到了Spring容器,我们回到LoadBalancerAutoConfiguration类,看其中注入LoadBalancerInterceptor类到Spring容器的地方;

2)LoadBalancerInterceptor#intercept()方法拦截请求

在这里插入图片描述
LoadBalancerInterceptor类实现ClientHttpRequestInterceptor接口,其中只有一个核心方法:intercept()用于拦截通过RestTemplate执行的请求。
在这里插入图片描述

在intercept()方法中,会基于LoadBalancerRequestFactory创建出来一个对RestTemplate请求包装后的请求,并将请求转发给组合的LoadBalancerClient接口的实现类RibbonLoadBalancerClient#execute()方法去执行;

这里我们也就知道了真正执行RestTemplate请求方法的入口是RibbonLoadBalancerClient#execute()

下面我们就继续来看RibbonLoadBalancerClient#execute()里面都做了什么?

3、RibbonLoadBalancerClient执行请求

从LoadBalancerInterceptor#intercept()方法进入到RibbonLoadBalancerClient#execute()方法代码执行流程如下:
在这里插入图片描述
最终进入到RibbonLoadBalancerClient#execute()方法中会做三件事:

  1. 根据服务名从Ribbon自己的Spring子上下文中获取服务名对应的ApplicationContext,进而获取到ILoadBalancer;
  2. 根据负载均衡器ILoadBalancer从Eureka Client获取到的List<Server>中选出一个Server。
  3. 拼装真正的请求URI,做HTTP请求调用。

本文我们重点看一下如何获取到ILoadBalancer?

1)获取ILoadBalancer流程图总述

在这里插入图片描述

2)如何获取到ILoadBalancer?

进入到#RibbonLoadBalancerClient#getLoadBalancer(String serviceId)方法;

protected ILoadBalancer getLoadBalancer(String serviceId) {
    // 通过SpringClientFactory来获取对应的LoadBalancer
    return this.clientFactory.getLoadBalancer(serviceId);
}

其将请求交给SpringClientFactory的getLoadBalancer(String)方法处理:
在这里插入图片描述

看SpringClientFactory的类图:

在这里插入图片描述
SpringClientFactory继承自NamedContextFactory,所以super.getInstance(name, type)方法为NamedContextFactory#getInstance()方法:
在这里插入图片描述
SpringClientFactory不是spring包下的,而是spring cloud与ribbon整合代码的包(org.springframework.cloud.netflix.ribbon)下的;

  • 其对spring进行了一定程度上的封装,从spring里面获取bean的入口,都变成了这个spring cloud ribbon自己的SpringClientFactory;
  • 也就是说:对于每个服务名称,都会有一个独立的spring的ApplicationContext容器(体现在NamedContextFactory类的contexts属性中);

在这里插入图片描述

  • ApplicationContext中包含了自己这个服务的独立的一堆的组件,比如说LoadBalancer;
  • 如果要获取一个服务对应的LoadBalancer,其实就是在自己的那个ApplicationContext里获取LoadBalancer接口类型的实例化Bean;

在这里插入图片描述
默认可以通过父类NamedContextFactory的getLoadBalacner()方法获取到ILoadBalancer接口对应的实例ZoneAwareLoadBalancer。即获取到的ILoadBalancer为ZoneAwareLoadBalancer

1> 为什么默认实例化的ILoadBalancer是ZoneAwareLoadBalancer?

spring-cloud-netflix-ribbonjar包下找到RibbonClientConfiguration类,RibbonClientConfiguration类中加载了的ILoadBalancer的实例bean --> ZoneAwareLoadBalancer:

在这里插入图片描述

默认的LoadBalancer是ZoneAwareLoadBalancer,ZoneAwareLoadBalancer类图如下:
在这里插入图片描述

ZoneAwareLoadBalancer继承自DynamicServerListLoadBalancer,DynamicServerListLoadBalancer继承自BaseLoadBalancer。

三、后续文章

下一篇文章,我们继续分析:

  • ZoneAwareLoadBalancer(属于ribbon)如何与eureka整合,通过eureka client获取到对应注册表?
  • ZoneAwareLoadBalancer如何持续从Eureka中获取最新的注册表信息?
  • 如何根据负载均衡器ILoadBalancer从Eureka Client获取到的List<Server>中选出一个Server?
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
23天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
25天前
|
运维 Kubernetes Cloud Native
云原生技术:容器化与微服务架构的完美结合
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术以其灵活性和高效性成为企业的新宠。本文将深入探讨云原生的核心概念,包括容器化技术和微服务架构,以及它们如何共同推动现代应用的发展。我们将通过实际代码示例,展示如何在Kubernetes集群上部署一个简单的微服务,揭示云原生技术的强大能力和未来潜力。
|
1月前
|
弹性计算 Kubernetes Cloud Native
云原生架构下的微服务设计原则与实践####
本文深入探讨了在云原生环境中,微服务架构的设计原则、关键技术及实践案例。通过剖析传统单体架构面临的挑战,引出微服务作为解决方案的优势,并详细阐述了微服务设计的几大核心原则:单一职责、独立部署、弹性伸缩和服务自治。文章还介绍了容器化技术、Kubernetes等云原生工具如何助力微服务的高效实施,并通过一个实际项目案例,展示了从服务拆分到持续集成/持续部署(CI/CD)流程的完整实现路径,为读者提供了宝贵的实践经验和启发。 ####
|
1月前
|
负载均衡 算法 应用服务中间件
5大负载均衡算法及原理,图解易懂!
本文详细介绍负载均衡的5大核心算法:轮询、加权轮询、随机、最少连接和源地址散列,帮助你深入理解分布式架构中的关键技术。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
5大负载均衡算法及原理,图解易懂!
|
28天前
|
负载均衡 监控 网络协议
SpringCloud之Ribbon使用
通过以上步骤,就可以在Spring Cloud项目中有效地使用Ribbon来实现服务调用的负载均衡,提高系统的可靠性和性能。在实际应用中,根据具体的业务场景和需求选择合适的负载均衡策略,并进行相应的配置和优化,以确保系统的稳定运行。
47 15
|
22天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
43 5
|
24天前
|
Kubernetes 负载均衡 Cloud Native
云原生架构下的微服务治理策略
随着云原生技术的不断成熟,微服务架构已成为现代应用开发的主流选择。本文探讨了在云原生环境下实施微服务治理的策略和方法,重点分析了服务发现、负载均衡、故障恢复和配置管理等关键技术点,以及如何利用Kubernetes等容器编排工具来优化微服务的部署和管理。文章旨在为开发者提供一套实用的微服务治理框架,帮助其在复杂的云环境中构建高效、可靠的分布式系统。
32 5
|
24天前
|
负载均衡 监控 Cloud Native
云原生架构下的微服务治理策略与实践####
在数字化转型浪潮中,企业纷纷拥抱云计算,而云原生架构作为其核心技术支撑,正引领着一场深刻的技术变革。本文聚焦于云原生环境下微服务架构的治理策略与实践,探讨如何通过精细化的服务管理、动态的流量调度、高效的故障恢复机制以及持续的监控优化,构建弹性、可靠且易于维护的分布式系统。我们将深入剖析微服务治理的核心要素,结合具体案例,揭示其在提升系统稳定性、扩展性和敏捷性方面的关键作用,为读者提供一套切实可行的云原生微服务治理指南。 ####
|
23天前
|
Cloud Native API 持续交付
云原生之旅:从容器到微服务的演进之路
【10月更文挑战第39天】在这篇文章中,我们将一起探索云原生技术的奥秘。通过浅显易懂的语言和生动的比喻,我们将了解云原生技术如何改变软件开发的世界。文章将带领读者从容器的基本概念出发,逐步深入到微服务架构的实践,揭示这些技术如何助力现代应用的快速迭代与可靠部署。准备好,让我们启程进入云原生的精彩世界吧!
|
28天前
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
50 5