【微服务六】Ribbon负载均衡策略之轮询(RoundRobinRule)、重试(RetryRule)
  Xa9NVipNa2Vn 2023年11月02日 89 0


文章目录

一、前言

前置Ribbon相关文章:

  1. ​【云原生&微服务一】SpringCloud之Ribbon实现负载均衡详细案例(集成Eureka、Ribbon)​
  2. ​【云原生&微服务二】SpringCloud之Ribbon自定义负载均衡策略(含Ribbon核心API)​
  3. ​【云原生&微服务三】SpringCloud之Ribbon是这样实现负载均衡的(源码剖析@LoadBalanced原理)​
  4. ​【云原生&微服务四】SpringCloud之Ribbon和Erueka集成的细节全在这了(源码剖析)​
  5. ​【微服务五】Ribbon随机负载均衡算法如何实现的​

我们聊了以下问题:

  1. 为什么给RestTemplate类上加上了@LoadBalanced注解就可以使用Ribbon的负载均衡?
  2. SpringCloud是如何集成Ribbon的?
  3. Ribbon如何作用到RestTemplate上的?
  4. 如何获取到Ribbon的ILoadBalancer?
  5. ZoneAwareLoadBalancer(属于ribbon)如何与eureka整合,通过eureka client获取到对应注册表?
  6. ZoneAwareLoadBalancer如何持续从Eureka中获取最新的注册表信息?
  7. 如何根据负载均衡器​​ILoadBalancer​​​从Eureka Client获取到的​​List<Server>​​中选出一个Server?
  8. Ribbon如何发送网络HTTP请求?
  9. Ribbon如何用IPing机制动态检查服务实例是否存活?
  10. Ribbon负载均衡策略之随机(RandomRule)实现方式;

本文继续讨论 轮询(RoundRobinRule)、重试(RetryRule)是如何实现的?

PS:Ribbon依赖Spring Cloud版本信息如下:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.7.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--整合spring cloud-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--整合spring cloud alibaba-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

二、轮询算法 --> RoundRobinRule

我们知道Ribbon负载均衡算法体现在IRule的choose(Object key)方法中,而choose(Object key)方法中又会调用​​choose(ILoadBalancer lb, Object key)​​​方法,所以我们只需要看各个IRule实现类的​​choose(ILoadBalancer lb, Object key)​​方法;

【微服务六】Ribbon负载均衡策略之轮询(RoundRobinRule)、重试(RetryRule)_spring


随机算法体现在RoundRobinRule#​​incrementAndGetModulo()​​方法:

private AtomicInteger nextServerCyclicCounter;

private int incrementAndGetModulo(int modulo) {
// 死循环直到获取到一个索引下标
for (;;) {
// 获取当前AtomicInteger类型变量的原子值
int current = nextServerCyclicCounter.get();
// 当前原子值 + 1 然后对 服务实例个数取余
int next = (current + 1) % modulo;
// CAS修改AtomicInteger类型变量,CAS成功返回next,否则无限重试
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}

轮询算法很简单,重点在于通过AtomicInteger原子类型变量 + 死循环 CAS操作实现,每次返回​​原子类型变量的当前值 + 1​​​,因为原子类型变量可能超过服务实例数,所以每次对原子类型变量赋值时,都会对其和服务实例总数​​做取余运算​​。

三、重试算法 --> RetryRule

进入RetryRule的​​choose(ILoadBalancer lb, Object key)​​方法;

【微服务六】Ribbon负载均衡策略之轮询(RoundRobinRule)、重试(RetryRule)_微服务_02

方法的核心逻辑:

  1. 首先记录开始要选择一个服务实例时的时间(即:开始请求时间为当前时间),和允许获取到服务实例的deadline,​​deadline为当前时间 + 500ms​​;
  2. 接着使用RetryRule组合的​​RoundRobinRule​​轮询选择一个服务实例;
  3. 如果选择的服务实例为空并且当前时间还没到deadline 或 选择的服务实例不是活着的并且当前时间还没到deadline,则进行重试、重新获取一个服务实例;
  4. 重试之前会先启动一个延时(deadline-当前时间)执行的定时任务,其中负责到deadline时中断当前线程;
  5. 死循环(当前线程不是中断状态时),调用RoundRobin算法选择一个服务实例,如果这个服务实例是有效的 或 当前时间过了截止时间,则跳出循坏;并取消上面新建的延时执行的定时任务,返回当前实例;
  6. 如果服务实例不是活着的并且当前时间在截止时间之内,则调用​​Thread.yield()​​​,让出线程资源,使当前线程 或 相同优先级的其他线程可以获取运行机会,也就是说​​yield的线程​​有可能被线程调度程序再次选中执行。

所以:RetryRule在subRule.choose(String)获得无效的服务实例后,会一直重试,但重试次数取决于​​重试的deadline​​​、​​当前线程相同优先级的其他线程个数​​。


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
Xa9NVipNa2Vn