Spring Cloud Alibaba Ribbon实现负载均衡

2022-06-18 11:46:17

负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。

Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix Ribbon 实现。通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模版请求自动转换成客户端负载均衡的服务调用。

Spring Cloud Ribbon 虽然只是一个工具类框架,它不像服务注册中心、配置中心、API 网关那样需要独立部署,但是它几乎存在于每一个 Spring Cloud 构建的微服务和基础设施中。因为微服务间的调用,API 网关的请求转发等内容,实际上都是通过 Ribbon 来实现的

一、使用

Ribbon在Spring Cloud 中的使用非常简单,因为我们的Nacos已经集成了Ribbon,这里我们就不需要再额外的引入jar包了。
只需要在RestTemplate的bean配置上加上注解@LoadBalanced

@Bean@LoadBalancedpublic RestTemplaterestTemplate(){returnnewRestTemplate();}

在我们使用RestTemplate做服务调用的时候就会自动进行负载均衡。

二、测试负载

  1. 启动两个provider,

在这里插入图片描述
2. 调用
在这里插入图片描述
在这里插入图片描述
从结果可以看到9001与9003都接受到了请求。负载成功。

三、Ribbon组件

接口作用默认值
IClientConfig读取配置DefaultClientConfigIpml
IRule负载均衡规则,选择实例ZoneAvoidanceRule
Iping筛选掉ping不通的实例DummyPing
ServerList交给Ribbion的实例列表Spring Cloud Alibaba : NacosServerList
ServerListFilter过滤掉不符合条件的实例ZonePreferenceServerListFilter
ILoadBalancerRibbon入口ZoneAwareLoadBalance
ServerListUpdater更新交给Ribbon的List的策略PollingServerListUpdater

四、Ribbon负载策略

上面提到IRule组件,我们找下该接口的具体实现

策略描述
AvailabilityFilteringRule过滤掉一直连接失败的被标记为circuit tripped(电路跳闸)的后端Service,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤Server的逻辑,其实就是检查status的记录的各个Server的运行状态
BestAvailableRule选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过
RandomRule 随机选择一个Server
ResponseTimeWeightedRule已废弃,作用同WeightedResponseTimeRule
RetryRule对选定的负责均衡策略机上充值机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的Server
RoundRobinRule轮询选择,轮询index,选择index对应位置Server
WeightedResponseTimeRule根据相应时间加权,相应时间越长,权重越小,被选中的可能性越低
ZoneAvoidanceRule(默认是这个)负责判断Server所Zone的性能和Server的可用性选择Server,在没有Zone的环境下,类似于轮询(RoundRobinRule)

五、更换不通负载策略

这里我们配置轮训策略
在这里插入图片描述
请求测试
在这里插入图片描述
这里我们可以看出,9001与9003轮流提供服务。

我们也可以自己实现IRule来自定义负载均衡策略。

六、Ribbon源码分析

6.1 为什么加上@LoadBalance之后才能把服务名转换为host:port

因为我们是通过@LoadBalanced注解来实现负载均衡的,那么首先看下注解@LoadBalanced的源码
在这里插入图片描述
从描述我们能看到,这个注解是让RestTemplate 去使用LoadBalancerClient

接着我们找下LoadBalancerClient的源码
在这里插入图片描述
LoadBalancerClient是spring cloud 定义的一个负载均衡器客户端接口,就是如果你要提供负载均衡支持,就必须要实现这个接口。
在这里插入图片描述
我们可以看到RibbonLoadBalancerClient实现了该接口。
接着往下看该接口定义的方法:
T execute(String serviceId, LoadBalancerRequest request) throws IOException
从负载均衡器中选择一个服务实例来执行请求。

URI reconstructURI(ServiceInstance instance, URI original);
这个方法就比较重要了,先看下描述
在这里插入图片描述
从描述我们看出,这个方法是把服务名称转换为host:port,这也就是为啥只要在使用了@LoadBalance,我们才能使用服务名称调用服务。解释了上一篇 服务调用最后抛出的结论

6.2 Ribbon默认负载策略是?

我们继续来看LoadBalancerClient接口,可以很容易的找到,只有Ribbon的RibbonLoadBalancerClient类实现了这个接口。在这里插入图片描述
我们可以看到这个类的execute方法中,通过调用getServer来获取一个Server,接着往下跟
在这里插入图片描述
这个是重点,他是使用Ribbon自定义的一个ILoadBalancer接口来获取具体实例的,我们进入的这个接口
在这里插入图片描述
接口中定义了,增加服务,选择服务,通知服务下线,获取服务列表等方法
继续往下跟,找接口的实现类,
在这里插入图片描述
我们可以看到BaseloadBalancer类实现了基础的负载均衡,而DynamicServerListLoadBalancer和ZoneAwareLoadBalancer在负载均衡的策略上做了一些功能的扩展。

在BaseLoadBalancer类中定义了IRule
在这里插入图片描述
我们可以看到在BaseLoadBalance中默认定义的为随机策略,但是上面我们说了,Ribbon默认的策略是ZoneAvoidanceRule
接下来我们找一下RibbonClientConfiguration类,在这个类我们我们可以看到定义了一个IRule
在这里插入图片描述
这就是为啥默认的负载策略为ZoneAvoidanceRule。

接着我们看下IRule的实现类
在这里插入图片描述
从名字我们可以看出RandomRule表示随机策略、RoundRobinRule表示轮询策略、WeightedResponseTimeRule表示加权策略、BestAvailableRule表示请求数最少策略等等。
具体实现这里就不看了。

6.3 Ribbon中的拦截器是如何被加进去的

我们可以看到在LoadBalancerClient所在包的目录有一个类LoadBalancerAutoConfiguration,通过名字我们能看出这是LoadBalance的配置类。
在这里插入图片描述
通过注解我们可以发现,Ribbon实现负载均衡自动化配置,要求:

  • RestTemplate必须在当前的工程环境中,
  • 在Spring的Bean工程中必须有LoadBalancerClient的实现bean。

改配置类主要做了三件事:

  • 创建了一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。
  • 创建了一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadbalancerInterceptor,需要注意的是,这个bean上的注解@ConditionalOnMissingBean,如果已经有RestTemplateCustomizer在BeanFactory的时候,这个bean就不会被创建,这里打断点我们可以看到,这段代码并没有被执行,RestTemplateCustomizer是在RibbonAutoConfiguration这个类中被创建的;
  • 维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器。

Ribbon的源码还有很多没有跟,像RibbonClientConfiguration等等,在我们遇到具体问题的时候来扒一扒源码,基本都能找到答案。

  • 作者:Gideon丶M
  • 原文链接:https://blog.csdn.net/mqqqq_1/article/details/113256732
    更新时间:2022-06-18 11:46:17