SpringCloud解析之Ribbon
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的更多相关文章
- SpringCloud学习之Ribbon
一.负载均衡与Ribbon 负载均衡,在集群中是很常见的一个“名词”,顾名思义是根据一定的算法将请求分摊至对应的服务节点上,常见的算法有如下几种: 轮询法:所有请求被依次分发到每台应用服务器上,每台服 ...
- SpringCloud解析之Zuul(二)
本文基于Spring Cloud Edgware.SR6,Zuul版本1.3.1,解析Zuul的请求拦截机制,让大家对Zuul的原理有个大概的认识和了解.如有不对的地方,欢迎指正. 在上一期的Spri ...
- SpringCloud+Eureka+Feign+Ribbon的简化搭建流程,加入熔断,网关和Redis缓存[2]
目录 前提:本篇是基于 SpringCloud+Eureka+Feign+Ribbon的简化搭建流程和CRUD练习[1] 的修改与拓展 1.修改consumer的CenterFeign.java,把返 ...
- 【SpringCloud】Netflix源码解析之Ribbon:负载均衡策略的定义和实现
Ribbon负载均衡策略定义 IRule其实就只做了一件事情Server choose(Object key),可以看到这个功能是在LB中定义(要求)的,LB把这个功能委托给IRule来实现.不同的I ...
- SpringCloud | FeignClient和Ribbon重试机制区别与联系
在spring cloud体系项目中,引入的重试机制保证了高可用的同时,也会带来一些其它的问题,如幂等操作或一些没必要的重试. 今天就来分别分析一下 FeignClient 和 Ribbon 重试机制 ...
- SpringCloud学习(4)——Ribbon负载均衡
Ribbon概述 SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具. 简单的说, Ribbon是Netflix发布的开源项目, 主要功能是提供客户端软 ...
- SpringCloud 进阶之Ribbon和Feign(负载均衡)
1. Ribbon 负载均衡 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端,负载均衡的工具; 1.1 Ribbon 配置初步 1.1.1 修改 micros ...
- SpringCloud教程二:Ribbon(Finchley版)
在上一篇文章,讲了服务的注册和发现.在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式,一种是ribbon+r ...
- spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign
基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...
随机推荐
- C# TCP 通讯
//接收 using System; using System.Collections.Generic;using System.ComponentModel;using System.Data;us ...
- 修改window.external使JS可调用Delphi方法
原文地址:http://hi.baidu.com/rarnu/blog/item/4ec80608022766d663d986ea.html 在js中,有一个比较特殊的对象,即window.exter ...
- 高手问答精选:Go 语言 —— 云计算时代的 C 语言(类似于一个FAQ)
Go 语言被称为云计算时代的 C 语言,它在软件开发效率和运行效率之间做出了绝佳的权衡.这使得它既适应于互联网应用的极速开发,又能在高并发.高性能的开发场景中如鱼得水.正因如此,许多互联网公司,尤其是 ...
- websocket协议学习
一 实验代码 client.html websocket_server.go package main import ( "crypto/sha1" "encoding/ ...
- win10 uwp 如何打包Nuget给其他人
原文:win10 uwp 如何打包Nuget给其他人 本文告诉大家,如果自己有做一些好用的库,如何使用 Nuget 打包之后上传,分享给大家. 首先需要知道一些 Nuget 打包需要知道的,请看 wi ...
- GIS基础软件及操作(四)
原文 GIS基础软件及操作(四) 练习四.空间数据处理 1.空间数据处理(融合.合并.剪切.交叉.合并)2.设置地图投影及投影变换 空间数据处理 数据:云南县界.shp; Clip.shp西双版纳森林 ...
- Android零基础入门第13节:Android Studio配置优化,打造开发利器
原文:Android零基础入门第13节:Android Studio配置优化,打造开发利器 是不是很多同学已经有烦恼出现了?电脑配置已经很高了,但是每次运行Android程序的时候就很卡,而且每次安装 ...
- Docker镜像与容器命令 专题
https://yeasy.gitbooks.io/docker_practice/content/install/mirror.html docker的工作流程图: 至少需要配备三样东西去使用doc ...
- C++函数不写bool返回值,居然编译运行全部通过,但判断结果就不对了
bool MyStart::IsCoorectParam(QString strParam) { if (strParam=="-aa" || strParam=="-b ...
- CDC-更改数据捕获存储过程 (Transact-SQL)-学习
背景: 在SQLServer2008之前,对数据变更的捕获通常使用触发器.时间戳等低效高成本的功能来实现,所以很多系统都没有做数据变更或者仅仅对核心表做监控. 适用环境: 仅在SQLServer200 ...


