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. siliverlight某些事件无法响应

    对一些无法响应的时间,需要注册 控件名:XZWT_TreeViewItem 事件:this.XZWT_TreeViewItem_MouseLeftButtonDown 具体注册方法: XZWT_Tre ...

  2. seajs教程(一):基本用法

    介绍 SeaJS 是一个适用于 Web 浏览器端的模块加载器.使用 SeaJS,可以更好地组织 JavaScript 代码. Sea.js 遵循 CMD 规范,模块化JS代码.依赖的自动加载.配置的简 ...

  3. <转>C# 动态创建DataTable

    C# 动态创建DataTable,有时候在做些测试Demo中用来模拟一些数据比较不错.记在这里避免以后重写呵呵... DataTable dt = new DataTable(); dt.Column ...

  4. Win10如何设置开机自动登录

    原文:Win10如何设置开机自动登录 第一步: 小娜搜索"netplwiz",进入用户账户设置. 第二步: 先勾选选中一次,要使用本计算机,用户必须输入用户名和密码. 第三步: 取 ...

  5. Win8Metro(C#)数字图像处理--2.9图像均值滤波

    原文:Win8Metro(C#)数字图像处理--2.9图像均值滤波  [函数名称] 图像均值滤波函数MeanFilterProcess(WriteableBitmap src) [函数代码]    ...

  6. linux的自动化操作相关使用方法汇总 专题

    Crontab中的除号(slash)到底怎么用? crontab 是Linux中配置定时任务的工具,在各种配置中,我们经常会看到除号(Slash)的使用,那么这个除号到底标示什么意思,使用中有哪些需要 ...

  7. LINQ查询表达式---------group子句

    LINQ查询表达式---------group子句 LINQ表达式必须以from子句开头,以select或group子句结束.使用guoup子句来返回元素分组后的结果.group 子句返回一个 IGr ...

  8. NuGet安装包重新安装

    Update-Package -reinstall 引用: https://docs.microsoft.com/zh-cn/nuget/consume-packages/reinstalling-a ...

  9. Windows 10 (IIS 10)安装Microsoft Web Farm Framework Version 2.2 for IIS7问题

    But I got an error message "iis version 7.0 or greater is required to install Web Farm Framewor ...

  10. Database time zone version is 18. It is older than current release time zone version 26

    [oracle@raca1 12.2.0]$ sqlplus / as sysdba SQL Production :: Copyright (c) , , Oracle. All rights re ...