1 缘起
Spring稳步向前发展,功能迭代,Bug修复,
对于应用工程师而言,不同版本的Spring对于开发还是有不小的影响,
比如,服务熔断、负载均衡,
SpringCloud2020.0.3版本:
(1)使用新的熔断组件:Resilience4j替代Hystrix,
(2)使用自带的负载均衡LoadBalancer替代Ribbon,
不同项目中使用不同的SpringCloud版本,应用时,各自处理各自的,有很强的割裂感,
打算先从负载均衡器开始,对比分析一下Ribbon和LoadBalancer负载均衡器,
包括两者默认的负载均衡策略、如何找到默认的负载均衡规则、如何自定义负载均衡规则,
帮助读者理解和记忆,轻松应知识考核场景。
2 负载均衡
简单理解:雨露均沾,如下图所示。我认为理想情况下的“均”不是平均,而是合适,
合理利用机器资源,让每台机器的利用率都在合适的范围。
在不同的业务场景下,催生了不同的负载均衡策略,如随机、轮询、最小连接数策略等,
共同的目的是保证服务可用,合理利用集群中的机器资源。
Spring中常用的负载均衡器有:Ribbon和LoadBalancer,
本文也是针对这两种负载均衡器展开分析的。
版本说明:
Ribbon:2.3.0
LoadBalancer:3.0.3
3 Ribbon负载均衡器
Netflix出品。
3.1 负载均衡策略
这里仅列出负载均衡策略,不细讲,后续会另写文章分析。
序号 | 均衡策略 | 描述 |
---|---|---|
1 | AvailabilityFilteringRule | 可用过滤规则,先过滤出故障或并发请求大于阈值的服务实例,然后线性轮询其余的实例 |
2 | BestAvailableRule | 最优可用规则,过滤故障后的服务实例,选择并发量最小的实例 |
3 | RandomRule | 随机规则,随机选择 |
4 | RetryRule | 重试规则,从服务实例轮询获取服务,失败,则重新轮询实例 |
5 | RoundRobinRule | 轮询规则,从服务列表中顺序获取服务 |
6 | WeightedResponseTimeRule | 响应时间加权轮询 |
7 | ZoneAvoidanceRule | 最佳区域实例集合中选择性能最优的服务 |
3.2 默认负载均衡策略
AvailabilityFilteringRule,可用过滤规则。先过滤出故障或并发请求大于阈值的服务实例,
然后线性轮询剩余的实例,分配请求。
3.2.1 入口类
老规矩,找到入口,Ribbon构造负载均衡器入口源码如下图所示。
位置:com.netflix.loadbalancer.LoadBalancerBuilder
由源码可知,并没有注释,见名知意,这就是构建负载均衡器的入口类,有默认配置config,自定义配置rule等属性。
3.2.2 构建负载均衡策略方法
构建负载均衡器的具体实现(入口)方法源码如下图所示,
位置:com.netflix.loadbalancer.LoadBalancerBuilder#buildFixedServerListLoadBalancer
由源码可知,并且为了分析方便,特将构建负载均衡器可分为4个步骤,如下图的标号,
(1)构建负载均衡器;
(2)创建负载均衡规则;
(3)创建Rule;
(4)获取默认规则;
3.2.2.1 第二步:创建负载均衡规则
通过这个配置,可以获取负载均衡默认属性,如负载均衡器、负载均衡规则等,
config的值,源码如下图所示,
位置:com.netflix.client.config.DefaultClientConfigImpl#getClientConfigWithDefaultValues()
有源码可知,配置的默认属性为getClientConfigWithDefaultValues()。
进入这个方法:getClientConfigWithDefaultValues(),
看到默认的负载均衡器DEFAULT_PROPERTY_NAME_SPACE,
源码如下图所示,由源码可知,使用的默认均衡器为ribbon,通过DefaultClientConfigImpl配置默认属性。
(1)默认的负载均衡器:ribbon
位置:com.netflix.client.config.DefaultClientConfigImpl#DEFAULT_PROPERTY_NAME_SPACE
(2)默认属性配置实现
位置:com.netflix.client.config.DefaultClientConfigImpl#DefaultClientConfigImpl(java.lang.String)
com.netflix.client.config.DefaultClientConfigImpl#loadDefaultValues
通过loadDefaultValues配置默认属性,如下图所示,默认的负载均衡规则Rule,在第三步讲。
DefaultClientConfigImpl中的属性properties用于存储默认属性值,如下图所示,具体的set和get感兴趣的可以继续看下源码,
这里仅给出部分过程和结果。
3.2.2.2 第三步:创建规则Rule
上面分析了填充默认属性值,接下来就可以获取配置以加载负载均衡器,
通过get获取对应的规则类名称,源码如下图所示,
由源码知,默认的Rule的键为:IClientConfigKey.Keys.NFLoadBalancerRuleClassName,
位置:com.netflix.loadbalancer.LoadBalancerBuilder#createRuleFromConfig
这个键对应的值是什么呢?
找到配置属性的地方,源码如下图所示,
由源码知,默认的规则类名称通过getDefaultNfloadbalancerRuleClassname()获取。
位置:com.netflix.client.config.DefaultClientConfigImpl#loadDefaultValues
默认规则类名称源码如下图所示,
由源码知,默认的负载均衡规则为:
位置:com.netflix.client.config.DefaultClientConfigImpl#getDefaultNfloadbalancerRuleClassname
3.3 自定义负载均衡策略
通过上面分析可知Ribbon默认会使用AvailabilityFilteringRule负载均衡策略,
虽然比较繁琐,但是,自定义配置负载均衡策略就比较方便了,
直接构造IRule类型的Bean即可,自定义构造负载均衡策略测试样例如下:
package com.company.microserviceuser.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 负载均衡策略配置.
*
* @author xindaqi
* @since 2022-09-01 18:17
*/
@Configuration
public class LoadBalancerConfig {
/**
* 轮询策略.
*
* @return 轮询对象
*/
@Bean
public IRule loadBalancerRule() {
return new RoundRobinRule();
}
}
4 Loadbalancer负载均衡器
Spring出品。
4.1 负载均衡策略
序号 | 均衡策略 | 描述 |
---|---|---|
1 | RandomRule | 随机规则,随机选择 |
2 | RoundRobinRule | 轮询规则,从服务列表中顺序获取服务 |
4.2 默认负载均衡策略
RoundRobinLoadBalancer,轮询策略。
默认的配置源码如下图所示,
由源码可知,默认的负载均衡策略为RoundRobinLoadBalancer。
位置:org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration
4.3 自定义负载均衡
自定义负载均衡策略参照官方源码,
因为,当前版本的负载均衡器只有两种均衡策略,
所以,自定义的策略为随机均衡策略,
配置样例如下:
package com.monkey.tutorial.common.config;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* 负载均衡策略配置.
*
* @author xindaqi
* @since 2022-09-01 18:13
*/
@Configuration
public class LoadBalancerConfig {
/**
* 随机负载均衡策略.
*
* @param environment 环境配置
* @param loadBalancerClientFactory 负载均衡客户端工厂
* @return 随机负载均衡对象
*/
@Bean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
5 小结
(1)负载均衡器:Ribbon和LoadBalancer,其中,Ribbon是Netflix开发,LoadBalancer是Spring官方的项目;
(2)Ribbon均衡器有7中均衡策略,LoadBalancer(3.0.3)有2中均衡策略;
(3)Ribbon默认均衡策略为:可用过滤规则;LoadBalancer默认策略为轮询。