Ribbon使用

在平时使用Ribbon时,更多的是将Ribbon与RestTemplate相结合:

   @Bean@LoadBalancedRestTemplate restTemplate(){return new RestTemplate();}
复制代码

首先定义一个RestTemplate,通过注解注入,同时注解也完成了负载均衡。

同时去使用restTemplate进行Rest调用

    @Overridepublic String hiService(String name){return restTemplate.getForObject("http://SERVER-HI/hi?name="+name,String.class);}
复制代码

那么在我们在输入http://localhost:8770/hi?name=lixin后,到底做了什么

一、封装

首先,在进行getForObject方法后,会将带入的url进行封装,封装成http请求request,然后被拦截器LoadBalancerInterceptor进行拦截,代码分别是:

@Override@Nullablepublic <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);HttpMessageConverterExtractor<T> responseExtractor =new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger);return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);}
复制代码

二、拦截

以及拦截部分:将request拦截下,截取其中URL及服务名,用于之后调用负载均衡方法时,选择合适的服务实例

    @Overridepublic ClientHttpResponse intercept(final HttpRequest request, final byte[] body,final ClientHttpRequestExecution execution) throws IOException {final URI originalUri = request.getURI();String serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));}
复制代码

三、根据负载均衡器调用服务实例

至此,调用RibbonLoadBalancerClient中的execute方法,先查看一下RibbonLoadBalancerClient类:

其中LoadBalancerClient接口,有如下三个方法,其中excute()为执行请求,reconstructURI()用来重构url。

ServiceInstanceChooser接口,主要有一个方法,用来根据serviceId来获取ServiceInstance。

它继承了ServiceInstanceChooser及LoadBalancerClient类,最终的负载均衡的请求处理,由它来执行

首先,去获取需要加载的负载均衡策略,通过getLoadBalancer方法执行,默认是轮询RoundRobbinRule方式:

在获取到负载均衡策略之后,通过getServer()方法去获取实例,点击进入getServer方法,发现是ILoadBalancer类去选择服务实例。

在ILoadBalancer接口中,addServers()方法是添加一个Server集合;chooseServer()方法是根据key去获取Server;markServerDown()方法用来标记某个服务下线;getReachableServers()获取可用的Server集合;getAllServers()获取所有的Server集合。

chooseServer则是由BaseLoadBalancer类进行实现:

根据代码可以看出,具体choose方法是根据不同的负载均衡策略,会有不同的选择方法,返回具体根据策略得到的服务实例。

最后根据服务实例,进行请求的调用。

负载均衡策略

IRule用于复杂均衡的策略,它有三个方法,其中choose()是根据key 来获取server,setLoadBalancer()和getLoadBalancer()是用来设置和获取ILoadBalancer的

IRule有很多默认的实现类,这些实现类根据不同的算法和逻辑来处理负载均衡。Ribbon实现的IRule有以下几个。在大多数情况下,这些默认的实现类是可以满足需求的,如果有特性的需求,可以自己实现。

  • BestAvailableRule 选择最小请求数
  • ClientConfigEnabledRoundRobinRule 轮询
  • RandomRule 随机选择一个server
  • RoundRobinRule 轮询选择server
  • RetryRule 根据轮询的方式重试
  • WeightedResponseTimeRule 根据响应时间去分配一个weight ,weight越低,被选择的可能性就越低
  • ZoneAvoidanceRule 根据server的zone区域和可用性来轮询选择

RoundRobbinRule

那我们就先看看RoundRobbinRule类中的轮询策略:

①首先获取所有存活的服务列表reachableServers及所有服务列表allServers,判断两个list是否为空。 ②incrementAndGetModulo中则是对一个原子性变量进行+1操作,并同时进行一个CAS操作,去修改nextServerIndex值,保证轮询的可靠性。
③最后判断服务是否可用,如果不可用,则重新进入循环。
④如果在10次循环后,仍然没有可用的服务,则退出循环并进行警告。最后返回服务实例

RetryRule

可重试的轮询策略如下:

可见此处多了两行代码:

long requestTime = System.currentTimeMillis();
long deadline = requestTime + maxRetryMillis;
复制代码

定义了500ms的总重试时间,如果服务实例获取不到,则进入循环,在循环中每次需要判断一下是否超过总时间

if判断中,嵌套了一个定时任务,去判断是否达到预定时间,如果达到了,则对当前线程进行interrupt()操作

while循环中,每次都会去获取一下服务实例,然后进行判断,如果实例仍然没有获取到,则对当前线程进行Thread.yield()操作,此操作的意义是:让出当前线程时间分片,重新争夺时间片,让定时任务去执行,看是否达到规定时间,如到时间,则执行interrupt()操作,退出循环

这即是可重试的策略

总体流程

Ribbon + RestTemplate 的负载平衡,流程是: 通过注解后,对url进行封装request,拦截器对request进行拦截,然后根据负载均衡器去调用服务实例,完成负载平衡和服务调用

SpringCloud Ribbon源码探索学习相关推荐

  1. SpringCloud ribbon源码

    1. 基本使用 server.port=8080spring.application.name=ribbon-clientxxx-server.ribbon.listOfServers=localho ...

  2. 万字长文浅析SpringCould微服务负载均衡框架Ribbon源码(字多慎入)

    前言 版本 作者:韩数 Github:github.com/hanshuaikan- 完成日期:2019-06-16日 jdk:1.8 springboot版本:2.1.3.RELEASE Sprin ...

  3. rust墙壁升级点什么_分享:如何在阅读Rust项目源码中学习

    今天做了一个Substrate相关的小分享,公开出来. 因为我平时也比较忙,昨天才选定了本次分享的主题,准备比较仓促,细节可能不是很充足,但分享的目的也是给大家提供一个学习的思路,更多的细节大家可以在 ...

  4. 跟大家聊聊我们为什么要学习源码?学习源码对我们有用吗?(源码感悟)

    来自:源码笔记 1 前言 由于现在微服务很流行,越来越多企业采用了SpringCloud微服务架构,而SpringBoot则是快速构建微服务项目的利器.于是笔者以此为切入点,将SpringBoot作为 ...

  5. 为什么要学习源码?学习源码对我们有用吗?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1 前言 由于现在微服务很流行,越来越多企业采用了Spr ...

  6. SpringCloud组件 源码剖析:Eureka服务注册方式流程全面分析

    在SpringCloud组件:Eureka服务注册是采用主机名还是IP地址?文章中我们讲到了服务注册的几种注册方式,那么这几种注册方式的源码是怎么实现的呢?我们带着这一个疑问来阅读本章内容能够让你更深 ...

  7. 深入分析Ribbon源码分析

    本文来分析下Ribbon源码 文章目录 Ribbon源码分析 负载均衡器 AbstractLoadBalancer BaseLoadBalancer DynamicServerListLoadBala ...

  8. Golang源码探索----GC的实现原理(6)

    推荐文章: Golang源码探索----GC的实现原理(1) Golang源码探索----GC的实现原理(2) Golang源码探索----GC的实现原理(3) Golang源码探索----GC的实现 ...

  9. 一个免费开源、跨平台的可视化源码探索项目

    [公众号回复 "1024",免费领取程序员赚钱实操经验] 今天我章鱼猫给大家推荐一个查看源码的神器,超级棒! Sourcetrail,它是一个免费开源.跨平台的可视化源码探索项目. ...

最新文章

  1. 200 个工具分析机器学习十年:开源是大势,工程师是核心
  2. CollegeStudent
  3. python输出到文件
  4. linux常见基本命令
  5. spring + maven项目 互相依赖的小坑
  6. 怎么安装jdk和java_如何安装JAVA JDK?
  7. 知乎上已获千赞,全网独家首发!
  8. php mysql注册登录界面_php实现登录注册界面
  9. max232管脚讲解 单片机与PC通讯
  10. Prism4翻译笔记(四)第四章:模块化应用程序开发
  11. Docker中配置国内镜像
  12. spss26没有典型相关性分析_SPSS执行典型相关性分析,出现下面错误,怎么回事??...
  13. python实现白色背景转为透明背景
  14. 复合函数高阶求导公式_复合函数求导公式有哪些
  15. 四面楚歌,商汤科技该如何在AI领域破局
  16. A链接标签点击不会触发任何行为的写法
  17. 控制IE浏览器升级降级
  18. 山东理工大学计算机期末考试题,山东理工大学计算机基础试题11
  19. 名帖367 邓文原 章草《临皇象急就章》
  20. 机器学习算法系列之K近邻算法

热门文章

  1. 《Windows via C/C++》学习笔记 —— Windows 线程池
  2. C++11 基于范围的 for 循环
  3. 图解使用CURL下载和上传文件
  4. ns2的第一个tcl脚本
  5. redis(nosql数据库)
  6. webpack搭建自己的项目
  7. 有关单例模式懒汉式安全的问题(全)
  8. Solr学习之一 --------环境搭建
  9. Json对象与Json字符串互转(4种转换方式)
  10. C#中的Infinity有个小坑