【DUBBO】dubbo的LoadBalance接口

LoadBalance负载均衡, 负责从多个 Invokers中选出具体的一个Invoker用于本次调用,调用过程中包含了负载均衡的算法,调用失败后需要重新选择

--->类注解@SPI说明可以基于Dubbo的扩展机制进行自定义的负责均衡算法实现,默认是随机算法方法注解@Adaptive说明能够生成设配方法Select方法设配类通过url的参数选择具体的算法, 在从invokers集合中根据具体的算法选择一个invoker

--->方法注解@Adaptive说明能够生成设配方法 Select方法设配类通过url的参数选择具体的算法, 在从invokers集合中根据具体的算法选择一个invoker

 

1. RandomLoadBalance: 随机访问策略,按权重设置随机概率,是默认策略

1)获取所有invokers的个数

2)遍历所有Invokers, 获取计算每个invokers的权重,并把权重累计加起来每相邻的两个invoker比较他们的权重是否一样,有一个不一样说明权重不均等

3)总权重大于零且权重不均等的情况下,按总权重获取随机数offset = random.netx(totalWeight);遍历invokers确定随机数offset落在哪个片段(invoker上)

4)权重相同或者总权重为0, 根据invokers个数均等选择invokers.get(random.nextInt(length))

 

      

2. RoundRobinLoadBalance:轮询,按公约后的权重设置轮询比率

1)获取轮询key  服务名+方法名

获取可供调用的invokers个数length

设置最大权重的默认值maxWeight=0

设置最小权重的默认值minWeight=Integer.MAX_VALUE

2)遍历所有Inokers,比较出得出maxWeight和minWeight

3)如果权重是不一样的

根据key获取自增序列

自增序列加一与最大权重取模默认得到currentWeigth

遍历所有invokers筛选出大于currentWeight的invokers

设置可供调用的invokers的个数length

4)自增序列加一并与length取模,从invokers获取invoker

 

 

3. LeastActiveLoadBalance: 最少活跃调用数, 相同的活跃的随机选择,

活跃数是指调用前后的计数差, 使慢的提供者收到更少的请求,因为越慢的提供者前后的计数差越大。

活跃计数的功能消费者是在ActiveLimitFilter中设置的

4. 最少活跃的选择过程如下:

1)获取可调用invoker的总个数

初始化最小活跃数,相同最小活跃的个数

相同最小活跃数的下标数组

等等

2)遍历所有invokers, 获取每个invoker的获取数active和权重

找出最小权重的invoker

如果有相同最小权重的inovkers, 将下标记录到数组leastIndexs[]数组中

累计所有的权重到totalWeight变量

3)如果invokers的权重不相等且totalWeight大于0

按总权重随机offsetWeight = random.nextInt(totalWeight)

计算随机值在哪个片段上并返回invoker

4)如果invokers的权重相等或者totalWeight等于0,均等随机

 

 

5. ConsistentHashLoadBalance:一致性hash, 相同参数的请求总是发到同一个提供者,当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。对于一致性哈希算法介绍网上很多

 

 

 

==============================个人学习============================

【一】Dubbo的四种负载均衡算法学习

package com.sxf.test.dubbo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Dubbo默认实现的四种负载均衡的算法解析
 * @author sxf
 *
 */
public class TestDubboLoadBalance {
    private static Random random = new Random();

    
    public static void main(String[] args) {
        //随机负载的策略
        //testRandomLoadBalance();
        
        //轮询的策略
        testRoundRobinLoadBalance();
    }
    
    
    /**
     * Dubbo基于随机和权重算法实现的随机负载均衡的核心算法
     */
    public static void testRandomLoadBalance(){
        List<Invoker> invokers=new ArrayList<Invoker>();
        //a机器
        Invoker a=new Invoker();
        a.setName("a");
        a.setWeight(100);
        
        //b机器
        Invoker b=new Invoker();
        b.setName("b");
        b.setWeight(300);
        
        //c机器
        Invoker c=new Invoker();
        c.setName("c");
        c.setWeight(800);
        
        //添加机器列表
        invokers.add(a);
        invokers.add(b);
        invokers.add(c);
        int length=3;//三台机器
    
        //权重不同的算法
        if(false){
            int totalWeight=1200;//三台机器总权重
            int offset=random.nextInt(totalWeight);//随机一个小于总权重的数字
            System.out.println("基于本次总权重随机出来的数字:"+offset);
            for(int i=0;i<length;i++){
                offset-=invokers.get(i).getWeight();
                if(offset<0){
                    System.out.println("本次被负载到的机器为:"+invokers.get(i).getName() +" ,权重为:"+invokers.get(i).getWeight() );
                    return;
                }
            }
        }

        //权重相同则按随机数,随机到那台机器,就是那台机器
        int index=random.nextInt(length);
        System.out.println("机器列表中随机一个数字为:"+index);
        System.out.println("本次被负载到的机器为:"+invokers.get(index).getName());
    }
    
    
    
    
    
    
    /**
     * Dubbo的轮询调用策略算法
     * 
     * dubbo的轮询策略,是基于【本次调用列表的list集合的下标=调用次数%服务列表个数】实现每个服务都循环调用。
     * 唯独不同的是,对权重大的服务列表多轮询一次。是通过对最大权重进行取余数操作一次,刨除本轮轮询小权重的服务列表。
     * 
     * 
     */
    public static   void testRoundRobinLoadBalance(){
        //key代表集群中的一个服务提供者的一个接口,value表示走当前消费服务器调用服务提供者的调用次数
        Map<String,AtomicInteger> sequences=new ConcurrentHashMap<String,AtomicInteger>();
        sequences.put("provider", new AtomicInteger());
        
        //服务集群列表
        List<Invoker> invokers=new ArrayList<Invoker>();
        
        int length=4;
        //a机器
        Invoker a=new Invoker();
        a.setName("a");
        a.setWeight(100);
        
        //b机器
        Invoker b=new Invoker();
        b.setName("b");
        b.setWeight(300);
        
        //c机器
        Invoker c=new Invoker();
        c.setName("c");
        c.setWeight(800);
        
        //d机器
        Invoker d=new Invoker();
        d.setName("d");
        d.setWeight(800);
        
        //添加机器列表
        invokers.add(a);
        invokers.add(b);
        invokers.add(c);
        invokers.add(d);
        
        //调用次数统计
        Map<String,Integer> map=new HashMap<String, Integer>();
        
        //模拟100次调用,服务提供者总共有4台机器
        for(int i=0;i<100;i++){
            String key="provider";//服务提供者的key
            AtomicInteger integer=sequences.get(key);
            int count=integer.get();
            integer.compareAndSet(count,count+1);
            //获取本次调用的服务
            Invoker invoker=invokers.get(count%length);
            
            //统计本次调用服务的次数
            Integer m=map.get(invoker.getName());
            if(m==null){
                map.put(invoker.getName(), new Integer(1));
            }else{
                int newc=m.intValue()+1;
                map.put(invoker.getName(), new Integer(newc));
            }
        }
        
        //打印每次服务的调用次数
        for(String key:map.keySet()){
            System.out.println("服务【"+key+"】的调用次数"+map.get(key));
        }
    }
    
    /**
     * 最小活跃次数,每一个服务在调用的时候,都会通过Filter
     * com.alibaba.dubbo.rpc.filter.ActiveLimitFilter
     * com.alibaba.dubbo.rpc.filter.ActiveLimitFilter.ExecuteLimitFilter
     * 向全局的com.alibaba.dubbo.rpc.RpcStatus中统计当前调用服务提供者的活跃次数
     * 
     * 每次在负载均衡的时候,都会通过当前服务列表去RpcStatus中拿到自己的活跃数。
     * 形成一个最小活跃数的数组 int[] lestActive中记录最小活跃数或相同最小活跃数的在当前服务列表的下标。
     * 如果最后最小活跃数只有一个服务提供者,则本次负载均衡就走这台服务器
     * 如果最后最小活跃数相同的,就在数组中随机一个下标,从服务列表的List集合中取出一个,负载均衡到这台服务器
     * 
     */
    public static void testLeastActiveLoadBalance(){
        //下面是伪代码
        List<Invoker> invokers=new ArrayList<Invoker>();
        int length=invokers.size();
        int[] leastIndexs = new int[length]; 
        int  lestActive=-1;//最小活跃数
        int lestActiveCount=0;
        for(int i=0;i<invokers.size();i++){
            Invoker invoker=invokers.get(i);
            Integer active=1;//从RpcStatus中拿到当前invoker的活跃次数
            if(lestActive==-1||active<lestActive){
                lestActive=active;
                leastIndexs[0]=i;
            }else if(active==lestActive){
                leastIndexs[lestActiveCount++]=i;
            }
        }
        //从相同的最小活跃数中随机选举出一个负载到这台机器上
        Invoker invoker=invokers.get(leastIndexs[random.nextInt(lestActiveCount)]);
    }
    
    /**
     * 这个是通过你对服务提供者接口配置调用服务的参数列表,进行hash运算,然后在服务列表中基于一致性hash算法,(hash环),算出负载到那台机器节点。
     * 结果,就是相同参数的调用,最终会一直被负载均衡到同一个机器节点上。前提是机器节点的个数不变。
     * 
     * 配置如:

<dubbo:service interface="..." loadbalance="consistenthash" />
或:

<dubbo:reference interface="..." loadbalance="consistenthash" />
或:

<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="consistenthash"/>
</dubbo:service>
或:

<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="consistenthash"/>
</dubbo:reference>


缺省只对第一个参数Hash,如果要修改,请配置
<dubbo:parameter key="hash.arguments" value="0,1" />

缺省用160份虚拟节点,如果要修改,请配置
<dubbo:parameter key="hash.nodes" value="320" />
     */
    public static void testConsistentHashLoadBalance(){
        
    }
}


/**
 * 代表服务的机器节点
 * @author sxf
 *
 */
class Invoker{
    //机器节点
    private String name;
    //权重
    private int weight;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
    
    
}
View Code
原文地址:https://www.cnblogs.com/shangxiaofei/p/7890287.html