无规则采集器列表算法( 本文介绍了的原理和实现细节介绍简介)
优采云 发布时间: 2021-11-22 04:05无规则采集器列表算法(
本文介绍了的原理和实现细节介绍简介)
负载均衡
本文介绍了负载均衡的原理和实现细节
1.简介
LoadBalance中文意思是负载均衡,它的职责是将网络请求或其他形式的负载“分担”到不同的机器上。避免出现集群中某些服务器压力过大而其他服务器空闲的情况。通过负载均衡,每个服务器都可以获得与其处理能力相适应的负载。在卸载高负载服务器的同时,也可以避免资源浪费,一石两用。负载均衡可分为软件负载均衡和硬件负载均衡。在我们日常开发中,一般很难接入硬件负载均衡。但是软件负载均衡还是可以的,比如Nginx。在 Dubbo 中,也有负载均衡的概念和相应的实现。Dubbo 需要对服务消费者的调用请求进行分配,避免少数服务提供者负载过大。服务提供者过载,这会导致一些请求超时。因此,非常有必要平衡各个服务提供商之间的负载。Dubbo 提供了四种负载均衡的实现,分别是基于加权随机算法的 RandomLoadBalance、基于最少活跃调用数算法的 LeastActiveLoadBalance、基于哈希一致性的 ConsistentHashLoadBalance 和基于加权轮询算法的 RoundRobinLoadBalance。这些负载均衡算法的代码都不是很长,但是理解起来并不容易。你需要对这些算法的原理有一定的了解。如果你不是很了解,也不要太担心。
本系列文章在写作之初基于Dubbo 2.6.4。最近,Dubbo 2.6.5 发布了,其中一些针对均衡部分的负载优化。因此,在分析完2.6. 4 版本之后的源码后,我们也会分析2.6.5 的更新部分。其他的就不多说了,进入正题。
2.源码分析
在 Dubbo 中,所有的负载均衡实现类都继承自 AbstractLoadBalance,它实现了 LoadBalance 接口并封装了一些常用的逻辑。所以在分析负载均衡的实现之前,我们先来看看AbstractLoadBalance的逻辑。先看负载均衡的入口方法select,如下:
@Override
public Invoker select(List invokers, URL url, Invocation invocation) {
if (invokers == null || invokers.isEmpty())
return null;
// 如果 invokers 列表中仅有一个 Invoker,直接返回即可,无需进行负载均衡
if (invokers.size() == 1)
return invokers.get(0);
// 调用 doSelect 方法进行负载均衡,该方法为抽象方法,由子类实现
return doSelect(invokers, url, invocation);
}
protected abstract Invoker doSelect(List invokers, URL url, Invocation invocation);
select方法的逻辑比较简单。首先检查调用者集合的有效性,然后检测调用者集合中元素的数量。如果只收录一个 Invoker,直接返回 Invoker。如果收录多个Invoker,则需要通过负载均衡算法选择一个Invoker。具体的负载均衡算法是由子类实现的,后面的章节将详细分析这些子类。
AbstractLoadBalance除了实现LoadBalance接口方法外,还封装了一些常用的逻辑,比如服务提供者权重计算逻辑。具体实现如下:
<p>protected int getWeight(Invoker invoker, Invocation invocation) {
// 从 url 中获取权重 weight 配置值
int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
if (weight > 0) {
// 获取服务提供者启动时间戳
long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
if (timestamp > 0L) {
// 计算服务提供者运行时长
int uptime = (int) (System.currentTimeMillis() - timestamp);
// 获取服务预热时间,默认为10分钟
int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
// 如果服务运行时间小于预热时间,则重新计算服务权重,即降权
if (uptime > 0 && uptime 0 && !sameWeight) {
// 随机获取一个 [0, totalWeight) 区间内的数字
int offset = random.nextInt(totalWeight);
// 循环让 offset 数减去服务提供者权重值,当 offset 小于0时,返回相应的 Invoker。
// 举例说明一下,我们有 servers = [A, B, C],weights = [5, 3, 2],offset = 7。
// 第一次循环,offset - 5 = 2 > 0,即 offset > 5,
// 表明其不会落在服务器 A 对应的区间上。
// 第二次循环,offset - 3 = -1 < 0,即 5 < offset < 8,
// 表明其会落在服务器 B 对应的区间上
for (int i = 0; i