Ribbon调用整体流程

在从源码底层去分析其实现原理之前,我们首先要知道Ribbon在工作过程中是怎样的一个流程,如下图:

相信用过Ribbin的同学(Feign底层也是封装的Ribbon)都知道Ribbon是一个用于客户端的服务发现负载均衡的调用组件,我们的服务提供者在启动的时候会主动向注册中心nacos(这里用nacos举例)去注册自己的信息,然后服务消费者通过加了@LoadBalance注解的RestTemplate组件向服务提供者发送调用请求,此时ribbon会解析这个host为服务名的url,取出host(调用的服务名),然后再去调用nacos client去nacos server中根据服务名去进行服务发现,取出该服务名对应的实例集合,然后ribbon再通过自己的负载均衡算法去选取其中的一个实例ip进行调用,这就是大概ribbon在调用的时候的流程。

Ribbon是如何干扰RestTemplate组件的调用?

在RestTemplate中能够添加一系列的Interceptor对我们的请求进行拦截处理相关的拦截逻辑,其实ribbon就是在RestTemplate中加入了相关的拦截器然后加入到容器中,而这个拦截器所做的工作就是上述流程,所以在我们使用加了@LoadBalance注解的RestTemplate组件的时候会被ribbon拦截器所拦截达到负载均衡的效果。

源码分析

接下来我们通过阅读源码去看上述的过程在代码是如何实现的。

1.什么时候在RestTemplate中放入了ribbon的Interceptor?

首先我们需要找到源码的入口,通常这些框架与springboot整合都是通过springboot的自动装配机制去整合的,所以入口也通常在一些XXXAutoConfiguration类里面,上面已经说了ribbon的核心实现流程主要是在RestTemplate中加入了ribbon的Interceptor来实现的,所以这个Interceptor应该就是入口了。来到@LoadBalance注解所在的包,我们能够发现一个LoadBalanceAutoConfiguration类,在里面发现一段配置:

这段代码把一个LoadBalancerInterceptor以及一个RestTemplateCustomizer加入到容器中,这个RestTemplateCustomzier就是一个RestTemplate的定制器,它里面对加入容器的RestTemplate添加了一个LoadBalancerInterceptor,但是这个定制器在什么时候会被调用呢?我们可以看到还有一个Bean的配置:

这段代码往容器里面添加了一个SmartInitializingSingleton,定制器就是在这个类的方法里面被执行的,首先拿到所有被@LoadBalanced接口注解的RestTemplate,然后遍历这些RestTemplate往里面执行我们的定制器的方法。那么这个类的方法又是什么时候执行的,熟悉Spring的同学应该知道,其实这个类是Spring中的一个接口类,在所有Bean都完成其生命周期的时候从容器找出所有实现了该接口的bean,然后执行这个接口的方法。

2.ribbon负载均衡的实现

这个Interceptor里面主要还是依靠LoadBalancerClient组件去执行的,这个组件我们通过一开始说的方法可以找到是在RibbonAutoConfiguration类中,并且是在上面说的LoadBalancerAutoConfiguration类执行之前去执行加入到容器中的

可以看到这个LoadBalancerClient是RibbonLoadBalancerClient,进去其excute方法中

这里有两句代码,很明显是首先拿到一个LoadBalancer的负载均衡器,然后通过这个负载均衡器去找到对应的某一个具体的服务的ip然后去进行调用,getLoadBalancer(serviceId)这句代码其实是从spring容器中去拿到对应的负载均衡器,所以肯定在某个配置类@Bean加入了一个具体的负载均衡器,通过寻找可以在RibbonClientConfiguration中找到

接着来到getServer里面的chooseServer方法,通过该方法名可以大概推断出该方法是用来选择具体的某一个服务的,进去父类的chooseServer

这里可以看到一句关键的代码,推断大概意思就是根据一定的规则去选择具体的服务,因为ribbon是提供多种规则或者自定义规则去选择服务的,而这个rule是一个接口所以具体的实现类大概又是在配置类中通过@Bean加入到容器中的了,也是在RibbonClientConfiguration中可以找到

大家注意下这些组件很多都是有@ConditionalOnMissingBean注解的所以需要的话我们也可以自己往容易中扔进去我们自己自定义的组件

但是这个类并没有choose方法,其实这个方法是在它的父类PredicateBasedRule中

关键代码就是红框中的代码

里面获取到所有可用的服务然后通过一个incrementAndGetModulo方法拿到服务集合的下标,可以看下该方法是通过什么规则拿的

这里使用了cas去防止并发问题,简单来说其实就是一个轮询规则,至此ribbon选择服务的流程就跑完了 。

2.ribbon拉取服务列表

我们上面说了ribbon是定时地从注册中心里面去拉取服务从而更新自己本地的服务列表,那么这个拉取的流程是怎样的呢?而且既然ribbon需要从注册中心去拉取服务列表,因为ribbon没有规定说一定要与哪个注册中心绑定在一起呀,那么当我们自己开发出一个注册中心的话,那么ribbon就肯定得提供相应的接口给注册中心去整合吧,下面我们来看看ribbon在与注册中心整合去实现拉取服务的过程。

首先我们知道这个拉取的过程不是我们自己去触发的,所以该拉取的源头肯定是在类初始化的时候,所以应该是在某个类的构造方法里面,当该类加入到容器中并且初始化成功之后去触发,仔细寻找其实是在初始化ZoneAwareLoadBalancer这个负载均衡器的时候它的父类DynamicServerListLoadBalancer有一个初始化方法去做的。

来到DynamicServerListLoadBalancer的构造方法中的restOfInit方法

这里我们重点关注红框中这两个方法,进去enableAndInitLearnNewServersFeature中

这里面的serverListUpdate其实也是在配置类中通过@Bean加入到容器中的

所以我们进去PollingServerListUpdater这个类的start方法中

这个方法就比较关键了,可以看出这个方法里面new了一个线程任务,然后通过线程池去延迟定时地去执行该任务,我们之前说过ribbon是定时地去从注册中心中拉取服务,可以看到这个初始延迟时间是1000ms,间隔执行时间30s,也就是说ribbon默认是隔30s去从注册中心拉取最新的服务列表的。而该任务中有一个重要的方法就是doUpdate,这个方法里面就是做从注册中心中拉取服务的事情了,进去doUpdate方法中

可以看到里面有一句serverListImpl.getUpdatedListOfServers的代码,这句代码就是从我们的注册中心中去拉取服务的,先找出serverListImpl的实现类

第一个类是从配置类中去通过@Bean去加载的

这个ServerList组件主要是读取IClientConfig里面set的serverList,而IClientConfig是在配置类中@Bean加入到容器的,默认里面set的serverList为空,所以如果我们单独使用ribbon的话,可以通过手动@Bean一个set了serverList的IConfig,从而让ribbon去读取自己手动set的serverList,但是我们通常都是去整合注册中心去使用,所以这种方式没什么意义

第二个ServerList组件我们可以看到一个特殊名字NacosServerList,这个组件就是nacos通过继承ribbon提供暴露出来的抽象类去实现的了,里面的逻辑就是调用nacos的客户端API去nacos服务端中拉取服务了

这里面的调用逻辑就是nacos客户端里面服务发现的源码了,这一块我们等看nacos源码的时候再去说吧

然后就是当ribbon每次从注册中心拿到了最新的服务列表去更新到本地

来到DynamicServerListLoadBalancer的父类BaseLoadBalancer,这个父类里面有一个全局变量

这个全局变量就是用来存储从注册中心拉取回来的最新的服务列表

继续看它的setServerList方法,可以看到有一句最关键的代码

把上面的存储服务列表的变量的引用指向了我们最新的获取到的服务列表集合,这就完成了本地服务列表缓存的更新了

下面通过一张图去说明ribbon各组件实现整个拉取服务负载均衡的流程

微服务调用组件Ribbon底层调用流程分析相关推荐

  1. 微服务01SpringCloud Eureka Ribbon Nacos Feign Gateway服务网关

    微服务技术栈导学 SpringCloud01 1.认识微服务 随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构.这些架构之间有怎样的差别呢? 1.0.学 ...

  2. 【微服务】Eureka+Ribbon实现注册中心与负载均衡

    文章目录 前言 1.微服务引入 1.1.相关概念 1.2.软件架构的演进 1.2.1.单体架构 1.2.2.垂直架构 1.2.3.分布式架构 1.2.4.SOA架构 1.2.5.微服务架构 1.3.S ...

  3. 【云原生微服务八】Ribbon负载均衡策略之WeightedResponseTimeRule源码剖析(响应时间加权)

    文章目录 一.前言 二.WeightedResponseTimeRule 1.计算权重? 1)如何更新权重? 2)如何计算权重? 3)例证权重的计算 2.权重的使用 1)权重区间问题? 一.前言 前置 ...

  4. 微服务、SOA 和 API对比与分析

    摘要: 对比微服务架构和面向服务的架构(SOA)是一个敏感的话题,常常引起激烈的争论.本文将介绍这些争论的起源,并分析如何以最佳方式解决它们.然后进一步查看这些概念如何与 API 管理概念结合使用,实 ...

  5. 微服务实践分享(8) 控制调用中心

    1.熔断 在微服务领域,熔断机制是从消费端保护微服务提供者的措施,当微服务的运行质量低于某个临界值时,启动熔断机制,暂停微服务调用一段时间,以保障后端的微服务不会因为持续过负荷而宕机. 2.降级 服务 ...

  6. 小程聊微服务-自己动手扩展分布式调用链

    一.说在前面 微服务是当下最火的词语,现在很多公司都在推广微服务,当服务越来越多的时候,我们是否会纠结以下几个问题: 面对一笔超时的订单,究竟是哪一步处理时间超长呢? 数据由于并发莫名篡改,到底都谁有 ...

  7. SylixOS中MTD调用底层接口流程分析

    1. MTD设备与底层驱动的关系   MTD设备是一种特殊的抽象设备,它用于简化驱动开发.它是底层硬件和上层软件的桥梁,无论对Nand Flash或是Nor Flash,它都提供了统一的框架供上层文件 ...

  8. 微服务的拆分和远程调用

    1.服务拆分原则 不同微服务,不要重复开发相同业务 微服务数据独立,不要访问其它微服务的数据库 微服务可以将自己的业务暴露为接口,供其它微服务调用 2.服务拆分示例 cloud-demo:父工程,管理 ...

  9. Spring cloud 微服务架构之Ribbon/Fegin连接超时ReadTimeout问题

    问题描述: 近期用Spring cloud 开发微服务架构时候,在服务与服务之间调用调试代码时候,出现链接超时. 错误信息: Read timed out executing GET http://s ...

  10. 微服务配置组件变色龙Archaius

    介绍 如果我们要设计开发一套微服务基础架构,大家觉得哪个组件是最基础的?基于多年互联网分布式系统的实战经验,我的回答是配置中心以及配套的客户端.之前我在极客时间上的课程<微服务架构和实践160讲 ...

最新文章

  1. centos 光盘 mysql_Centos6.5 使用光盘镜像系统源安装数据库mysql5.7
  2. linux shell数组深入学习理解
  3. 一起玩树莓派3+使用Gitlab搭建专业Git服务
  4. mysql主从数据库验证_数据库主从一致性验证
  5. ActiveReports 报表应用教程 (10)---交互式报表之向下钻取(详细数据按需显示解决方案)...
  6. (译)An introduction to Kubernetes
  7. python3 Unicode字符与16进制编码互转(单个字符)
  8. Xshell/Xftp个人完全免费版
  9. 甘特图怎么做项目进度计划
  10. 自然语言处理领域国内外著名会议和期刊
  11. 微信小程序开发:集成微信支付功能
  12. 概率论中的一些基础知识——条件概率 先验概率 后验概率 似然 概率分布函数 概率密度函数
  13. 每天一种设计模式之抽象工厂模式(Java实现)
  14. unity项目之太空大战(2)
  15. HDOJ题目分类大全
  16. Python 写入tsv文件
  17. php usc2,CSDN 免积分下载原理
  18. 测试工具AppScan安装使用
  19. JeecgBoot 3.4.4 版本发布,开源的企业级低代码平台
  20. CRMEB 微信商城系统 源码下载

热门文章

  1. 单片机用C语言锯齿波,试用c语言编写一个能输出锯齿波信号的单片机c51程序
  2. 浮动网页html特效代码,网页上可点击关闭的纯代码无图版浮动tips提示特效代码...
  3. 批量梯度下降算法BGD
  4. 在pcb放置坐标标注_PCB拼板上的那颗美人痣
  5. 求一个容器的最值的索引_初中几何最值——瓜豆原理模型分析
  6. Gibbs Sampling\吉布斯采样(二)
  7. Linux sed命令之删除文件第一行,第n行
  8. 当 p<1时,p 范数不满足三角不等式的证明 | p norm | triangle inequality
  9. Tomcat一直启动不成功,连接不到8080(持续更新带图解释并总结了其他博文)
  10. 2020教师计算机考试笔试题,2020年全国教师资格考试信息技术学科知识与能力练习题...