Dubbo 负载均衡策略

某电商平台的商品服务有 10 个实例,其中 2 个实例因为 GC 导致响应变慢(200ms),其他 8 个实例正常(5ms)。

使用默认的加权轮询负载均衡策略,2 个慢实例仍然被分配了相同的流量,导致整体 RT 飙高。

改用"最少活跃调用数"策略后,Dubbo 自动将流量分配到响应快的实例上,整体 RT 恢复正常。

【架构权衡】 负载均衡策略的选择直接影响系统的稳定性和响应时间。没有最好的策略,只有最适合业务的策略。响应时间稳定时用加权轮询,实例性能差异大时用最少活跃。


一、核心问题 🔴

1.1 六种负载均衡策略

策略原理适用场景
Random随机选择场景简单
WeightedRandom加权随机实例性能不同
RoundRobin轮询实例性能相同
WeightedRoundRobin加权轮询实例性能不同
LeastActive最少活跃调用响应时间差异大
ConsistentHash一致性哈希缓存友好

1.2 策略实现原理

// RandomLoadBalance
public class RandomLoadBalance extends AbstractLoadBalance {
    @Override
    protected <T> T doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        int length = invokers.size();
        boolean sameWeight = true;
        int[] weights = new int[length];
        int totalWeight = 0;

        for (int i = 0; i < length; i++) {
            int weight = getWeight(invokers.get(i), invocation);
            totalWeight += weight;
            weights[i] = totalWeight;

            if (sameWeight && i > 0 && weight != weights[i - 1]) {
                sameWeight = false;
            }
        }

        if (totalWeight > 0 && !sameWeight) {
            int offset = ThreadLocalRandom.current().nextInt(totalWeight);
            for (int i = 0; i < length; i++) {
                if (offset < weights[i]) {
                    return invokers.get(i);
                }
            }
        }

        return invokers.get(ThreadLocalRandom.current().nextInt(length));
    }
}

// LeastActiveLoadBalance
public class LeastActiveLoadBalance extends AbstractLoadBalance {
    @Override
    protected <T> T doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        int length = invokers.size();
        int leastActive = -1;
        int leastCount = 0;
        int[] leastIndexes = new int[length];

        for (int i = 0; i < length; i++) {
            Invoker<T> invoker = invokers.get(i);
            int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName())
                .getActive();

            if (active < leastActive || leastActive == -1) {
                leastActive = active;
                leastCount = 1;
                leastIndexes[0] = i;
            } else if (active == leastActive) {
                leastIndexes[leastCount++] = i;
            }
        }

        // 从最少活跃的实例中加权随机
        if (leastCount == 1) {
            return invokers.get(leastIndexes[0]);
        }
        // ...
    }
}

二、配置方式

dubbo:
  provider:
    loadbalance: leastactive  # 全局配置

# 方法级配置
dubbo:
  references:
    order-service:
      methods:
        - name: createOrder
          loadbalance: leastactive

三、落地 Checklist

  • 性能评估:评估各实例性能差异
  • 策略选择:根据业务选择合适的策略
  • 监控部署:监控各实例的调用量和响应时间
  • 动态调整:根据监控数据动态调整权重