zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    同台电脑 多Git账号同时使用
    netty对http协议解析原理解析(转载)
    Netty 线程模型与Reactor 模式
    增量/存量数据按时间维度分组
    网易技术分享:Nginx缓存引发的跨域惨案
    全面剖析Redis Cluster原理和应用
    聊聊阿里社招面试,谈谈“野生”Java程序员学习的道路
    美团点评基于 Flink 的实时数仓建设实践
    美团技术分享:大众点评App的短视频耗电量优化实战
    美团技术分享:美团深度学习系统的工程实践
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/7890287.html
Copyright © 2011-2022 走看看