您的位置:

Dubbo负载均衡详解

一、Dubbo负载均衡的几种方式

Dubbo支持以下几种负载均衡方式:

  • Random LoadBalance
  • RoundRobin LoadBalance
  • LeastActive LoadBalance
  • ConsistentHash LoadBalance
  • Forking LoadBalance
  • Failover LoadBalance
  • Failfast LoadBalance
  • Failsafe LoadBalance

具体说明如下:

  • Random LoadBalance:随机选择一个服务提供者。
  • RoundRobin LoadBalance:轮询选择服务提供者。
  • LeastActive LoadBalance:选取活跃调用数最小的服务提供者。
  • ConsistentHash LoadBalance:一致性哈希负载均衡算法。
  • Forking LoadBalance:并行调用多个服务提供者,只要有一个成功就返回。
  • Failover LoadBalance:失败自动切换到其他服务提供者,通常用于非幂等性的远程调用。
  • Failfast LoadBalance:失败快速失败,通常用于幂等性的远程调用。
  • Failsafe LoadBalance:失败安全,总是调用所有服务提供者,通常用于写入审计日志等操作。

二、Dubbo负载均衡策略

Dubbo负载均衡有两种策略,即随机和权重。下面给出Dubbo配置文件中的负载均衡配置示例:

  

这里设置负载均衡策略为随机,也可以设置为权重策略,示例如下:

  
  
   

  

三、Dubbo负载均衡源码

Dubbo负载均衡的源码在Dubbo的GitHub仓库中,查看地址为:https://github.com/apache/dubbo/tree/master/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance

四、Ribbon负载均衡

Ribbon是Netflix开源的负载均衡组件,Dubbo可以集成Ribbon实现负载均衡。Ribbon的负载均衡算法可以自定义实现,Dubbo使用的是RoundRobin策略,示例配置如下:

  

五、Dubbo协议

Dubbo协议是Dubbo RPC通信协议的实现,其主要特点如下:

  • Dubbo协议采用NIO异步通信、多路复用技术,可以提高吞吐量。
  • Dubbo协议支持长连接,减少连接建立的开销。
  • Dubbo协议支持多协议,可以在dubbo://、rest://等多种协议间切换。

六、Dubbo接口

Dubbo接口是Dubbo服务的提供方和消费方进行通信的契约。Dubbo服务提供者和消费者都必须引用相同的接口。

示例代码:

public interface DemoService {
    String sayHello(String name);
}

七、Dubbo负载均衡算法

Dubbo负载均衡算法有多种实现方式,例如RandomLoadBalance、RoundRobinLoadBalance等。下面给出RoundRobinLoadBalance的算法简述:

  1. 将所有可用服务提供者存入一个有序列表list
  2. 如果服务提供者列表为空,则返回空;如果只有一个服务提供者,则返回该服务提供者
  3. 如果服务提供者列表不为空,则获取下一个服务提供者并返回

其Java代码实现如下:

public class RoundRobinLoadBalance extends AbstractLoadBalance {

    private final AtomicPositiveInteger sequences = new AtomicPositiveInteger();
    
    protected  Invoker
    doSelect(List
    
     > invokers, URL url, Invocation invocation) {
        int length = invokers.size(); // 调用的服务数
        int maxWeight = 0;
        int minWeight = Integer.MAX_VALUE;
        final LinkedHashMap
      
       
        , IntegerWrapper> invokersWightMap = new LinkedHashMap
        
         
          , IntegerWrapper>(); int weightSum = 0; for (int i = 0; i < length; i++) { Invoker
          
           invoker = invokers.get(i); int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "weight", 100); invokersWightMap.put(invoker, new IntegerWrapper(weight)); weightSum += weight; maxWeight = Math.max(maxWeight, weight); minWeight = Math.min(minWeight, weight); } // 不同的权重转换为相同的权重 if (maxWeight > 0 && minWeight < maxWeight) { int weightDiff = maxWeight - minWeight; if (weightDiff > 0) { for (Map.Entry
           
            
             , IntegerWrapper> entry : invokersWightMap.entrySet()) { entry.setValue(new IntegerWrapper(entry.getValue().get() - minWeight)); } weightSum -= minWeight * length; } } // 循环列表进行轮转 int sequence = sequences.getAndIncrement(); if (weightSum > 0 && sequence < Integer.MAX_VALUE) { int currentWeight = -1; Invoker
             
              selectedInvoker = null; int currentSequence = -1; for (int i = 0; i < length; i++) { sequence++; if (sequence > weightSum) { sequence = weightSum; } for (Map.Entry
              
               
                , IntegerWrapper> entry : invokersWightMap.entrySet()) { selectedInvoker = entry.getKey(); currentWeight = entry.getValue().get(); currentSequence += currentWeight; if (currentSequence >= sequence) { return selectedInvoker; } } currentSequence = 0; } } // 相同权重,随机选择 return invokers.get(ThreadLocalRandom.current().nextInt(length)); } static class IntegerWrapper { private int value; public IntegerWrapper(int value) { this.value = value; } public int get() { return value; } public void set(int value) { this.value = value; } } }
               
              
             
            
           
          
         
        
       
      
     
    
   
  

八、Dubbo负载均衡原理

Dubbo负载均衡实现的原理如下:

  1. 获取所有可用服务提供者的列表,计算出他们的权重
  2. 根据负载均衡策略选择一个服务提供者
  3. 如果服务提供者无法响应,返回到第2步重新选择
  4. 返回选取的服务提供者

九、Dubbo负载均衡在哪层

Dubbo负载均衡在服务层,属于网络通信层。

十、Dubbo负载均衡策略如何配置选取

Dubbo负载均衡策略可以在Dubbo配置文件中进行配置,例如:

  

也可以通过代码进行动态设置,例如:

public class DemoConsumer {
    public static void main(String[] args) {
        ReferenceConfig reference = new ReferenceConfig
   ();
        reference.setInterface(DemoService.class);
        reference.setLoadbalance("roundrobin");
        DemoService demoService = reference.get();
        String hello = demoService.sayHello("world");
        System.out.println(hello);
    }
}