Ribbon是分布式微服务架构中负载均衡的一个解决方案,我们只需要引入ribbon依赖,然后初始化一个RestTemplate对象,在其上添加@LoadBalanced注解,就可以实现请求的负载均衡,像下面这样

RestTemplate是属于org.springframework.web.client包下,那么它是如何通过ribbon实现负载均衡的呢?
SpringBoot在启动时会加载spring-cloud-commons.jar中的一些自动化配置文件,其中有LoadBalancerAutoConfiguration,看名字大家可以猜到这个是负载平衡自动配置文件。
首先,它会将所有程序中有@LoadBalanced注解的RestTemplate实例放入一个集合,
然后创建一个负载平衡请求工厂LoadBalancerRequestFactory,这里传入的loadBalancerClient,其实是ribbon的RibbonLoadBalancerClient,它实现了
LoadBalancerClient接口
接着创建一个负载平衡拦截器LoadBalancerInterceptor,这里传入的就是上面的RibbonLoadBalancerClient和LoadBalancerRequestFactory

然后,遍历RestTemplate集合,给每一个RestTemplate实例添加上面创建好的LoadBalancerInterceptor

总结起来,LoadBalancerAutoConfiguration就是给所有@LoadBalanced注解的RestTemplate装上一个负载平衡拦截器LoadBalancerInterceptor。

之后,当发起请求执行restTemplate方法时,最后是执行的内部的doExecute方法,它创建的ClientHttpRequest其实是实现类InterceptingClientHttpRequest,最终调用的是InterceptingClientHttpRequest的内部类InterceptingRequestExecution的execute方法

这里,从拦截器的迭代器中取出的ClientHttpRequestInterceptor,其实是它的实现LoadBalancerInterceptor,这就是在LoadBalancerAutoConfiguration中set进去的,然后执行LoadBalancerInterceptor的intercept方法

在LoadBalancerInterceptor中,最后执行的loadBalancer.execute,是RibbonLoadBalancerClient的方法,别忘了,在LoadBalancerAutoConfiguration中创建的负载平衡拦截器LoadBalancerInterceptor,传入的初始化参数就是RibbonLoadBalancerClient

RibbonLoadBalancerClient.execute方法中,首先会根据serviceId获取负载平衡拦截器,然后将其传入getServer方法中

这里其实还是调用的拦截器的chooseServer方法,

最后,调用rule.choose方法,这里的rule是ribbon的负载平衡规则,ribbon的负载平衡规则有轮询,随机,响应时间权重,空闲这么几种,默认是轮询,可以通过配置指定规则,比如配置成权重MY-PROVIDER.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.WeightedResponseTimeRule

(具体每一种规则的逻辑就不在此细说,有兴趣的朋友可以自行查阅)。根据负载平衡规则获取到具体的Server实例后,将Server包装成RibbonServer,

继续走,

终于,最后,执行的是request.apply方法,这里的request就是LoadBalancerInterceptor.intercept方法中LoadBalancerRequestFactory.createRequest方法创建的request

跟着request.apply方法进来,发现将request包装成了ServiceRequestWrapper,但是这里并没有使用ribbon负载平衡后获取的服务实例instance,接着走,

发现又回到了InterceptingClientHttpRequest的内部类InterceptingRequestExecution的execute方法,

这时已经没有拦截器了,走到else中,要创建一个ClientHttpRequest,createRequest(request.getURI(), request.getMethod())中的request是上面的

ServiceRequestWrapper,我们看下它的getURI()逻辑

原来是在这里,调用了RibbonLoadBalancerClient.reconstructURI方法,在内部通过负载平衡获取的服务实例组装成具体的uri,在之后就是常规操作了,拼接请求头和请求参数,发起请求。

绕了一大圈,做下总结:

添加了@LoadBalanced注解的RestTemplate执行时,会进入LoadBalancerInterceptor的intercept方法,接着会进入ribbon的RibbonLoadBalancerClient类,在该类中通过serviceId获取负载平衡器,然后通过其内部的负载平衡规则获取具体的Server实例,最后回到InterceptingClientHttpRequest.execute方法,通过包装的ServiceRequestWrapper.getURI()方法,调用RibbonLoadBalancerClient.reconstructURI方法拼接具体的请求uri,然后执行http请求。

SpringCloud解析之Ribbon的更多相关文章

  1. SpringCloud学习之Ribbon

    一.负载均衡与Ribbon 负载均衡,在集群中是很常见的一个“名词”,顾名思义是根据一定的算法将请求分摊至对应的服务节点上,常见的算法有如下几种: 轮询法:所有请求被依次分发到每台应用服务器上,每台服 ...

  2. SpringCloud解析之Zuul(二)

    本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解.如有不对的地方,欢迎指正. 在上一期的Spri ...

  3. SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存[2]

    目录 前提:本篇是基于 SpringCloud+Eureka+Feign+Ribbon的简化搭建流程和CRUD练习[1] 的修改与拓展 1.修改consumer的CenterFeign.java,把返 ...

  4. 【SpringCloud】Netflix源码解析之Ribbon:负载均衡策略的定义和实现

    Ribbon负载均衡策略定义 IRule其实就只做了一件事情Server choose(Object key),可以看到这个功能是在LB中定义(要求)的,LB把这个功能委托给IRule来实现.不同的I ...

  5. SpringCloud | FeignClient和Ribbon重试机制区别与联系

    在spring cloud体系项目中,引入的重试机制保证了高可用的同时,也会带来一些其它的问题,如幂等操作或一些没必要的重试. 今天就来分别分析一下 FeignClient 和 Ribbon 重试机制 ...

  6. SpringCloud学习(4)——Ribbon负载均衡

    Ribbon概述 SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具. 简单的说, Ribbon是Netflix发布的开源项目, 主要功能是提供客户端软 ...

  7. SpringCloud 进阶之Ribbon和Feign(负载均衡)

    1. Ribbon 负载均衡 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端,负载均衡的工具; 1.1 Ribbon 配置初步 1.1.1 修改 micros ...

  8. SpringCloud教程二:Ribbon(Finchley版)

    在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...

  9. spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign

    基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...

随机推荐

  1. Spring Web Flow 的优缺点

    # 前言 Spring Web Flow = SWF 最近学习了<Spring实战>的第八章,Spring Web Flow.感觉是个不错的东西.无奈发现网上的资料少之又少.后来发现根本没 ...

  2. centos7安装 lamp

    1.安装apache yum install httpd #根据提示,输入Y安装即可成功安装 systemctl start httpd.service #启动apache systemctl sto ...

  3. Win10《芒果TV》商店版更新v3.1.3.0:优化应用速度,支持会员卡兑换

    在微软秋季Win10/Surface新品发布会热潮之后,<芒果TV>UWP版迅速更新v3.1.3版,优化应用启动速度,支持会员卡券兑换,新增全网搜索.记忆播放.消息推送等功能. 芒果TV ...

  4. C# Excel导入Access

    /// <summary> /// 导入 /// </summary> private void btn_In_Click(object sender, EventArgs e ...

  5. DHTMLEdit控件的安装

    xp中自带了DHTMLEdit.ocx, 所以只需安装即可 但是可视化设计面板中没有这个控件,需要我们手动安装一下 具体方式: [import AcitveX control  在控件板上的安装]一. ...

  6. 为什么使用剪切板时都用GlobalAlloc分配内存(历史遗留问题,其实没关系了)

    我在使用剪切板时,发现通用的都是使用GlobalAlloc来分配内存,我就想不是说在Win32中GlobalAlloc和LocalAlloc是一样的那为什么不用LocalAlloc呢,原谅我的好奇心吧 ...

  7. 使用VS2010开发Qt程序的4点经验(QT4到QT5的升级,更改sln文件,切换工程使用的Qt库,在VS的Solution Explorer视图中建立文件夹)

    导读 相比于Qt Creator,我更喜欢用VS2010来进行开发.虽然启动时间相对较慢,但是VS下强大的快捷键和丰富的插件,以及使用多年的经验,都让我觉得在开发过程中得心应手.其中最重要的一点是,有 ...

  8. Tuxera NTFS 2018 for Mac中文破解版 U盘读写软件-让你的Mac支持NTFS

    下载链接(复制到浏览器下载):http://h5ip.cn/TLMc 软件介绍 给大家带来一款苹果Mac上如何使用U盘读写的软件,Tuxera NTFS 2018 for Mac中文破解版,Mac O ...

  9. kafka笔记4(2)

    提交和偏移量 每次调用poll 方法,总是返回生产者写入Kafka但还没有被消费者读取过的记录我们因此可以追踪到哪些记录时被群组里的哪个消费者读取过的. 我们把更新分区当前位置的操作叫做提交. 那么消 ...

  10. shell多线程之进程间通信(3)

    之前的文章依赖是1对1或1多对的,但每个任务的前置任务都只有1个. 本文的核心在于一个任务依赖于多个任务的执行完成,如上图所示,这个任务就是fact,只有new和dviduser两个任务都完成的情况下 ...