红茶的个人站点

  • 首页
  • 专栏
  • 开发工具
  • 其它
  • 隐私政策
Awalon
Talk is cheap,show me the code.
  1. 首页
  2. Spring Cloud 学习笔记
  3. 正文

从零开始 Spring Cloud 3:负载均衡

2023年7月16日 1192点热度 0人点赞 0条评论

image-20230714102655393

图源:laiketui.com

在上一篇文章中我们介绍了如何使用 Eureka 作为注册中心,并且对注册中心里的服务使用 RestTemplate 做负载均衡调用。本篇文章我们来看负载均衡调用是如何实现的,以及如何设置其中的调度规则。

原理

源码分析

先启动项目的所有模块,其中 shopping-order 模块用 debug 模式启动。

然后在RestTemplate调用接口的地方打上断点,进行调试,一步步查看负载均衡是在何时发生的。

image-20230716090248025

最终我们会定位到一个InterceptingClientHttpRequest类:

image-20230716090808553

这个类的execute方法会从iterator中获取一个ClientHttpRequestInterceptor对象,并执行该对象的intercept方法执行实际的接口调用并返回结果。

image-20230716091040596

查看变量监控不难发现,迭代器中的元素是一个LoadBalanceInterceptor对象。

image-20230716091244658

LoadBalanceInterceptor.intercept方法中,会先通过原始的 Url 地址originalUri(这里是http://shopping-user/user/1)获取服务名serviceName(这里是shopping-user),然后再调用this.loadBalancer.execute执行真正的接口调用。

image-20230716091736441

this.loadBalancer的类型是BlockingLoadBalancerClient。

在BlockingLoadBalancerClient.execute方法中,最关键的一步是调用choose并传入服务名,返回一个ServiceInstance对象,这个对象代表一个具体的接口服务实例(在我们这个示例中,就是子模块 shopping-order 的两个已启动实例的其中之一)。换言之,这个choose方法是真正负责处理的“负载均衡”代码,它会从 Eureka 中查询服务名关联的服务实例,并按规则从中挑选一个实例用于后续的具体接口调用。

image-20230716091850962

BlockingLoadBalancerClient.choose方法中,先通过loadBalancerClientFactory.getInstance方法获取一个ReactiveLoadBalancer对象,这个对象代表负载均衡的规则。

image-20230716092725586

默认的规则是RoundRobinLoadBalancer,所以这里的loadBalancer是这个类型。

image-20230716093101847

ReactiveLoadBalancer是一个接口,RoundRobinLoadBalancer是一个实现,它们的继承关系如下:

image-20230716100252104

可以看到,还有另一个实现RandomLoadBalancer。

从名称就可以看出来,RoundRobinLoadBalancer是轮询策略,而RandomLoadBalancer是乱序(随机)策略。

总结

总结一下,上述过程中负责负载均衡过程可以表示为:

image-20230716103821040

  • BlockingLoadBalancerClient用于处理阻塞式的负载均衡调用,实际上 LoadBalancer 还可以处理响应式的负载均衡调用。

  • 早期的 Spring Cloud 和 Eureka 客户端使用 ribbon 作为负载均衡组件。教新版本的 Spring Cloud 中可以通过配置spring.cloud.ribbon.enabled控制是否使用 ribbon。

负载均衡策略

Spring Cloud 默认使用的负载均衡策略为轮询,对应RoundRobinLoadBalancer这个实现类。我们可以将其切换为乱序(随机)策略:

@Configuration
@LoadBalancerClient(value = "shopping-user", configuration = CustomLoadBalancerConfiguration.class)
public class WebConfig {
    // ...
}

这里的@LoadBalancerClient的value属性用于指定服务名,我们可以为不同的服务指定不同的负载均衡策略。configuration指定一个自定义负载均衡策略的类。

public class CustomLoadBalancerConfiguration {
    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

在配置类中添加一个ReactorLoadBalancer类型的 bean 工厂方法,并实际返回一个RandomLoadBalancer对象。

除了这种简单方式外,还可以利用ServiceInstanceListSupplier类制造一些功能更复杂的负载均衡策略,相关内容可以阅读这篇文章。

本文的完整示例代码见这里。

参考资料

  • 微服务生态组件之Spring Cloud LoadBalancer详解和源码分析 - itxiaoshen - 博客园 (cnblogs.com)

  • Spring Cloud LoadBalancer - 知乎 (zhihu.com)

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: LoadBalancer spring cloud 负载均衡
最后更新:2023年8月30日

魔芋红茶

加一点PHP,加一点Go,加一点Python......

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2021 icexmoon.cn. ALL RIGHTS RESERVED.
本网站由提供CDN加速/云存储服务

Theme Kratos Made By Seaton Jiang

宁ICP备2021001508号

宁公网安备64040202000141号