「SpringCloud原理」Ribbon核心组件以及运行原理万字源码剖析

作者&投稿:止丽 (若有异议请与网页底部的电邮联系)
~ 大家好,本文我将继续来剖析SpringCloud中负载均衡组件Ribbon的源码。本来我是打算接着OpenFeign动态代理生成文章直接讲Feign是如何整合Ribbon的,但是文章写了一半发现,如果不把Ribbon好好讲清楚,那么有些Ribbon的细节理解起来就很困难,所以我还是打算单独写一篇文章来剖析Ribbon的源码,这样在讲Feign整合Ribbon的时候,我就不再赘述这些细节了。好了,话不多说,直接进入主题。

这是个很简单的东西,就是服务实例数据的封装,里面封装了服务实例的ip和端口之类的,一个服务有很多台机器,那就有很多个Server对象。

ServerList是个接口,泛型是Server,提供了两个方法,都是获取服务实例列表的,这两个方法其实在很多实现类中实现是一样的,没什么区别。这个接口很重要,因为这个接口就是Ribbon获取服务数据的来源接口,Ribbon进行负载均衡的服务列表就是通过这个接口来的,那么可以想一想是不是只要实现这个接口就可以给Ribbon提供服务数据了?事实的确如此,在SpringCloud中,eureka、nacos等注册中心都实现了这个接口,都将注册中心的服务实例数据提供给Ribbon,供Ribbon来进行负载均衡。

通过名字也可以知道,是用来更新服务注册表的数据,他有唯一的实现,就是PollingServerListUpdater,这个类有一个核心的方法,就是start,我们来看一下start的实现。

通过这段方法我们可以看出,首先通过isActive.compareAndSet(false, true)来保证这个方法只会被调用一下,然后封装了一个Runnable,这个Runnable干了一件核心的事,就是调用传入的updateAction的doUpdate方法,然后将Runnable扔到了带定时调度功能的线程池,经过initialDelayMs(默认1s)时间后,会调用一次,之后都是每隔refreshIntervalMs(默认30s)调用一次Runnable的run方法,也就是调用updateAction的doUpdate方法。

所以这个类的核心作用就是每隔30s会调用一次传入的updateAction的doUpdate方法的实现,记住这个结论。

IRule是负责负载均衡的算法的,也就是真正实现负载均衡获取一个服务实例就是这个接口的实现。比如说实现类RandomRule,就是从一堆服务实例中随机选取一个服务实例。

就是一个配置接口,有个默认的实现DefaultClientConfigImpl,通过这个可以获取到一些配置Ribbon的一些配置。

这个接口的作用,对外主要提供了获取服务实例列表和选择服务实例的功能。虽然对外主要提供获取服务的功能,但是在实现的时候,主要是用来协调上面提到的各个核心组件的,使得他们能够协调工作,从而实现对外提供获取服务实例的功能。

这个接口的实现有好几个实现类,但是我讲两个比较重要的。

BaseLoadBalancer

核心属性

allServerList:缓存了所有的服务实例数据

upServerList:缓存了能够使用的服务实例数据。

rule:负载均衡算法组件,默认是RoundRobinRule

核心方法

setRule:这个方法是设置负载均衡算法的,并将当前这个ILoadBalancer对象设置给IRule,从这可以得出一个结论,IRule进行负载均衡的服务实例列表是通过ILoadBalancer获取的,也就是 IRule 和 ILoadBalancer相互引用。setRule(rule)一般是在构造对象的时候会调用。

chooseServer:就是选择一个服务实例,是委派给IRule的choose方法来实现服务实例的选择。

BaseLoadBalancer这个实现类总体来说,已经实现了ILoadBalancer的功能的,所以这个已经基本满足使用了。

说完BaseLoadBalancer这个实现类,接下来说一下DynamicServerListLoadBalancer实现类。DynamicServerListLoadBalancer继承自BaseLoadBalancer,DynamicServerListLoadBalancer主要是对BaseLoadBalancer功能进行扩展。

DynamicServerListLoadBalancer

成员变量

serverListImpl:上面说过,通过这个接口获取服务列表

filter:起到过滤的作用,一般不care

updateAction:是个匿名内部类,实现了doUpdate方法,会调用updateListOfServers方法

serverListUpdater:上面说到过,默认就是唯一的实现类PollingServerListUpdater,也就是每个30s就会调用传入的updateAction的doUpdate方法。

这不是巧了么,serverListUpdater的start方法需要一个updateAction,刚刚好成员变量有个updateAction的匿名内部类的实现,所以serverListUpdater的start方法传入的updateAction的实现其实就是这个匿名内部类。

那么哪里调用了serverListUpdater的start方法传入了updateAction呢?是在构造的时候调用的,具体的调用链路是调用 restOfInit -> enableAndInitLearnNewServersFeature(),这里就不贴源码了

所以,其实DynamicServerListLoadBalancer在构造完成之后,默认每隔30s中,就会调用updateAction的匿名内部类的doUpdate方法,从而会调用updateListOfServers。所以我们来看一看 updateListOfServers 方法干了什么。

这个方法实现很简单,就是通过调用 ServerList 的getUpdatedListOfServers获取到一批服务实例数据,然后过滤一下,最后调用updateAllServerList方法,进入updateAllServerList方法。

其实很简单,就是调用每个服务实例的setAlive方法,将isAliveFlag设置成true,然后调用setServersList。setServersList这个方法的主要作用是将服务实例更新到内部的缓存中,也就是上面提到的allServerList和upServerList,这里就不贴源码了。

其实分析完updateListOfServers方法之后,再结合上面源码的分析,我们可以清楚的得出一个结论,那就是默认每隔30s都会重新通过ServerList组件获取到服务实例数据,然后更新到BaseLoadBalancer缓存中,IRule的负载均衡所需的服务实例数据,就是这个内部缓存。

从DynamicServerListLoadBalancer的命名也可以看出,他相对于父类BaseLoadBalancer而言,提供了动态更新内部服务实例列表的功能。

为了便于大家记忆,我画一张图来描述这些组件的关系以及是如何运作的。

说完一些核心的组件,以及他们跟ILoadBalancer的关系之后,接下来就来分析一下,ILoadBalancer是在ribbon中是如何使用的。

ILoadBalancer是一个可以获取到服务实例数据的组件,那么服务实例跟什么有关,那么肯定是跟请求有关,所以在Ribbon中有这么一个抽象类,AbstractLoadBalancerAwareClient,这个是用来执行请求的,我们来看一下这个类的构造。

通过上面可以看出,在构造的时候需要传入一个ILoadBalancer。

AbstractLoadBalancerAwareClient中有一个方法executeWithLoadBalancer,这个是用来执行传入的请求,以负载均衡的方式。

这个方法构建了一个LoadBalancerCommand,随后调用了submit方法,传入了一个匿名内部类,这个匿名内部类中有这么一行代码很重要。

这行代码是根据给定的一个Server重构了URI,这是什么意思呢?举个例子,在OpenFeign那一篇文章我说过,会根据服务名拼接出类似 http:// ServerA 的地址,那时是没有服务器的ip地址的,只有服务名,假设请求的地址是 http:// ServerA/api/sayHello ,那么reconstructURIWithServer干的一件事就是将ServerA服务名替换成真正的服务所在的机器的ip和端口,假设ServerA所在的一台机器(Server里面封装了某台机器的ip和端口)是192.168.1.101:8088,那么重构后的地址就变成 http:// 192.168.1.101:8088/api/ sayHello ,这样就能发送http请求到ServerA服务所对应的一台服务器了。

之后根据新的地址,调用这个类中的execute方法来执行请求,execute方法是个抽象方法,也就是交给子类实现,子类就可以通过实现这个方法,来发送http请求,实现rpc调用。

那么这台Server是从获取的呢?其实猜猜也知道,肯定是通过ILoadBalancer获取的,因为submit方法比较长,这里我直接贴出submit方法中核心的一部分代码

就是通过selectServer来选择一个Server的,selectServer我就不翻源码了,其实最终还是调用ILoadBalancer的方法chooseServer方法来获取一个服务,之后就会调用上面的说的匿名内部类的方法,重构URI,然后再交由子类的execut方法来实现发送http请求。

所以,通过对AbstractLoadBalancerAwareClient的executeWithLoadBalancer方法,我们可以知道,这个抽象类的主要作用就是通过负载均衡算法,找到一个合适的Server,然后将你传入的请求路径 http:// ServerA/api/sayHello 重新构建成类似 http:// 192.168.1.101:8088/api/ sayHello 这样,之后调用子类实现的execut方法,来发送http请求,就是这么简单。

到这里其实Ribbon核心组件和执行原理我就已经说的差不多了,再来画一张图总结一下

说完了Ribbon的一些核心组件和执行原理之后,我们再来看一下在SpringCloud环境下,这些组件到底是用的哪些实现,毕竟有写时接口,有的是抽象类。

Ribbon的自动装配类:RibbonAutoConfiguration,我拎出了核心的源码

RibbonAutoConfiguration配置类上有个@RibbonClients注解,接下来讲解一下这个注解的作用

SpringClientFactory是不是感觉跟OpenFeign中的FeignContext很像,其实两个的作用是一样的,SpringClientFactory也继承了NamedContextFactory,实现了配置隔离,同时也在构造方法中传入了每个容器默认的配置类RibbonClientConfiguration。至于什么是配置隔离,我在OpenFeign那篇文章说过,不清楚的小伙伴可以后台回复feign01即可获得文章链接。

配置优先级问题

优先级最低的就是FeignContext和SpringClientFactory构造时传入的配置类

至于优先级怎么来的,其实是在NamedContextFactory中createContext方法中构建AnnotationConfigApplicationContext时按照配置的优先级一个一个传进去的。

RibbonClientConfiguration提供的默认的bean

接下来我们看一下RibbonClientConfiguration都提供了哪些默认的bean

配置类对应的bean,这里设置了ConnectTimeout和ReadTimeout都是1s中。

IRule,默认是ZoneAvoidanceRule,这个Rule带有过滤的功能,过滤哪些不可用的分区的服务(这个过滤可以不用care),过滤成功之后,继续采用线性轮询的方式从过滤结果中选择一个出来。至于这个propertiesFactory,可以不用管,这个是默认读配置文件的中的配置,一般不设置,后面看到都不用care。

至于为什么容器选择NacosServerList而不是ConfigurationBasedServerList,主要是因为NacosRibbonClientConfiguration这个配置类是通过@RibbonClients导入的,也就是比SpringClientFactory导入的RibbonClientConfiguration配置类优先级高。

ServerListUpdater,就是我们剖析的PollingServerListUpdater,默认30s更新一次BaseLoadBalancer内部服务的缓存。

那么在springcloud中,上图就可以加上注册中心。

三、总结

本文剖析了Ribbon这个负载均衡组件中的一些核心组件的源码,并且将这些组件之间的关系一一描述清楚,同时也剖析了在发送请求的时候是如何通过ILoadBalancer获取到一个服务实例,重构URI的过程。希望本篇文章能够让你知道Ribbon是如何工作的。


SpringCloud微服务架构下,分布式事务怎么处理?
尽管每个模式都有其适用场景,2PC协议(Prepare和Commit阶段)是目前主流的选择,它通过预提交和最终提交的两阶段操作,确保了事务的可靠性和完整性。在实践中,你需要根据业务需求和系统特性,灵活选择合适的分布式事务处理方法。总的来说,SpringCloud为微服务架构下的分布式事务提供了强大的工具和策略。通过...

SpringCloud微服务实战——搭建企业级开发框架(三十八):搭建ELK日 ...
在微服务架构中,日志分析系统是性能监控和问题定位的基石。Elasticsearch(存储)、Logstash(处理)和Kibana(展示)组成的ELK堆栈,配合Kafka处理高并发场景下的日志增长,Filebeat作为高效日志采集器,使得整个系统无缝协作。我们推荐使用以下版本:Elasticsearch 8.0.0, Logstash 8.0.0, Kibana 8.0.0, ...

springcloud有哪些主件
5、Config SpringCloud Config提供服务器端和客户端。服务器存储后端的默认实现使用git,因此它轻松支持标签版本的配置环境,以及可以访问用于管理内容的各种工具。这个还是静态的,得配合Spring Cloud Bus实现动态的配置更新。

springcloud断路器的作用
Spring Cloud断路器的作用是在微服务架构中,当某个服务出现故障或延迟过高时,暂时中断对该服务的调用,从而确保系统的整体稳定性和可靠性。一、背景与概念引入 在微服务架构中,各个服务之间是相互调用的。当某个服务出现故障,例如因为网络问题、服务过载、或者代码bug导致的问题,其他服务调用这个故障服务...

springcloud有哪些主件
Spring Cloud的主要组件包括服务注册与发现(Eureka),负载均衡(Ribbon),服务调用(Feign),断路器(Hystrix),路由网关(Zuul),配置管理(Config Server和Bus),服务跟踪(Sleuth)等。1. 服务注册与发现(Eureka):Eureka是Spring Cloud中的服务注册中心,它提供了一个平台,使得在分布式系统中的...

springcloud网关常见功能
Spring Cloud网关的常见功能包括路由、过滤器、负载均衡和服务发现。1. 路由:Spring Cloud网关作为微服务架构的入口,最重要的功能之一就是路由。它负责将来自客户端的请求路由到相应的服务。通过使用路由规则,网关可以将请求映射到正确的微服务上。例如,根据URL路径或请求头中的特定信息,网关可以决定将请求...

springcloud常见功能
1. 服务发现:在微服务架构中,服务发现是至关重要的一部分。Spring Cloud通过Netflix Eureka或者Consul等工具提供了服务发现的功能。这意味着,在一个复杂的系统中,每个服务都能自动找到其他服务,无需进行硬编码。比如,一个订单服务可能需要找到用户服务以验证用户信息,服务发现功能就能自动帮助它找到用户...

springcloud网关的常见功能
Spring Cloud网关的常见功能包括路由、过滤器、负载均衡和服务发现。1. 路由:Spring Cloud网关作为微服务架构的入口,最重要的功能之一就是路由。它负责将来自客户端的请求路由到相应的服务。通过使用路由规则,网关可以将请求映射到不同的微服务上。例如,根据请求的路径或请求头中的信息,网关可以判断将请求...

springcloud网关的作用是什么
Spring Cloud网关的主要作用是提供一个统一的入口点来管理和路由微服务架构中的请求。1. 统一管理入口点:在微服务架构中,通常有许多不同的微服务处理各种特定的业务功能。为了简化客户端的调用和管理,Spring Cloud网关作为统一入口点,处理所有外部请求,并将其路由到相应的微服务。这样,客户端只需与网关...

关于springcloud熔断机制说法错误的是
关于SpringCloud熔断机制,有以下几个说法:1.熔断机制的核心原理是内存中的断路器模式。这个说法是正确的,SpringCloud熔断机制基于Hystrix实现,其核心原理是内存中的断路器模式,用于应对系统潜在的雪崩效应,提供了一种简单而高效的处理方式。2.当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务...

兴城市13014415983: 西天取经,学 Spring - Cloud,到底什么是 Spring - Cloud -
弘桂复方: Spring Cloud 是Pivotal提 供的用于简化分布式系统构建的工具集.Spring Cloud引入了云平台连接器(Cloud Connector)和服务连接器(Service Connector)的概念.云平台连接器是一个接口,需要由云平台提供者进行实现,以便库中的其他模块可以与该云平台协同工作.

兴城市13014415983: spring cloud,基于什么实现 -
弘桂复方: Spring Cloud的子项目,大致可分成两类,一类是对现有成熟框架”Spring Boot化”的封装和抽象,也是数量最多的项目;第二类是开发了一部分分布式系统的基础设施的实现,如Spring Cloud Stream扮演的就是kafka, ActiveMQ这样的角色....

兴城市13014415983: 如何学习spring cloud -
弘桂复方: 使用Spring Cloud构建实际的微服务架构.基本概念:使用Docker进行集成测试混合持久化微服务架构服务发现API网关Docker使用Docker对每一个服务进行构建和部署.使用Docker Compose在一个开发机上进行端到端的集成测试....

兴城市13014415983: 如何使用Spring Boot/Spring Cloud 实现微服务应用 -
弘桂复方: Spring Cloud介绍 spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简...

兴城市13014415983: 如何使用Spring Cloud -
弘桂复方: Spring Cloud项目的既定目标在于为Spring开发人员提供一整套易于使用的工具集,从而保证其轻松构建起自己需要的分布式系统方案.为了实现这一目标,Spring Cloud以Netflix OSS堆栈为基础将大量实现堆栈加以整合并打包.这些堆栈而后...

兴城市13014415983: 如何调用spring cloud微服务 -
弘桂复方: spring-cloud调用服务有两种方式,一种是百Ribbon+RestTemplate, 另外一种是Feign.Ribbon是一个基于度HTTP和TCP客户端的负载均衡器,其实版feign也使用了ribbon, 只要使用@FeignClient时,权ribbon就会自动使用.

兴城市13014415983: Spring boot 与 Spring cloud 是什么关系 -
弘桂复方: ring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式. spring boot 的优点是可以快速启动,快速构建应用程序,而不需要太多的配置文件. spring cloud 是分布式开发的解决方案,基于spring boot,在spring boot做较少的配置, 便可成为 spring cloud 中的一个微服务.

兴城市13014415983: 现在为什么越来越多的公司要用Spring Cloud? -
弘桂复方: Spring作为企业应用构建的利器已深入人心,Spring Cloud提供一套分布式应用常见问题的解决方案,帮助企业应用迅速云化.华为在构建自己的微服务框架的过程中充分借鉴了Spring以及SpringCloud 的很多优秀思想.我们公司也在用,是和上海艾班仕合作的.

兴城市13014415983: 看Spring - cloud怎样使用Ribbon
弘桂复方: 关注下spring cloud是如何进行客户端负责均衡. 看怎么调用到负载均衡的,怎么定义负载均衡的,然后是怎么实现的?第一个其实可以不用关心,调用的地方应该很多,找到一个地方来说明怎么调用的即可. 第二个,可以猜下,最主要的应该...

兴城市13014415983: 哪位大神比较过spring cloud和dubbo,各自的优缺点是什么 -
弘桂复方: Spring Cloud主要有以下特点:1. 是一套完整的分布式系统解决方案,它的子项目涵盖了所有实现布式系统所需要的基础软件设施2. 基于Spring Boot, 使得开发部署极其简单(加依赖,加注解,就能运行了)要说Dubbo,算是Spring Cloud的一个子集好了,大致相当于Spring Cloud里的 Eureka + Feign + 1/2Hystrix另外,我认为Spring Cloud极有可能是未来Java生态中微服务架构实现的标配

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网