zoukankan      html  css  js  c++  java
  • rpc之负载均衡

    使用集群,比如zk来控制注册中心,当一个服务有多个请求地址的时候,会返回多个地址。

    那么就需要负载均衡来控制我们要请求哪台机器来得到请求。

    方案一:随机

    传入key值和key所包含的ip地址值,该地址值存入TreeSet中(有序存储)

    获得TreeSet的长度,然后随机得到其索引,挑出随机的一个。

     public String route(String serviceKey, TreeSet<String> addressSet) {
            // arr
            String[] addressArr = addressSet.toArray(new String[addressSet.size()]);
    
            // random
            String finalAddress = addressArr[random.nextInt(addressSet.size())];
            return finalAddress;
        }

    方案二:轮询

     TreeSet中的地址值存入一个数组中,并设置一个map集合来记录该函数调用了几次,每次调用,就将索引加1,然后返回该索引的地址值。这样就会按照TreeSet中的顺序依次选取请求地址。

    private ConcurrentHashMap<String, Integer> routeCountEachJob = new ConcurrentHashMap<String, Integer>();
        private long CACHE_VALID_TIME = 0;
        private int count(String serviceKey) {
            // cache clear
            if (System.currentTimeMillis() > CACHE_VALID_TIME) {
                routeCountEachJob.clear();
                CACHE_VALID_TIME = System.currentTimeMillis() + 24*60*60*1000;//一天的时间
            }
    
            // count++
            Integer count = routeCountEachJob.get(serviceKey);
            count = (count==null || count>1000000)?(new Random().nextInt(100)):++count;  // 初始化时主动Random一次,缓解首次压力
            routeCountEachJob.put(serviceKey, count);
            System.out.println("count:"+count);
            return count;
        }
    
        @Override
        public String route(String serviceKey, TreeSet<String> addressSet) {
            // arr
            String[] addressArr = addressSet.toArray(new String[addressSet.size()]);
    
            // round
            int i = count(serviceKey) % addressArr.length;
            System.out.println(i);
            String finalAddress = addressArr[i];
            return finalAddress;
        }

    方案三: LRU(最近最少使用调度算法)

    每次使用了每个节点的时候,就将该节点放置在最后面,这样就保证每次使用的节点都是最近最久没有使用过的节点,当节点数大于最大空间的时候,就直接将前面的节点删掉。

    实现:使用LinkedHashMap来实现。它内部有一个双向链表在维护

    public String doRoute(String serviceKey, TreeSet<String> addressSet) {
    
            // cache clear
            if (System.currentTimeMillis() > CACHE_VALID_TIME) {
                jobLRUMap.clear();
                CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;//一天
            }
    
            // init lru
            LinkedHashMap<String, String> lruItem = jobLRUMap.get(serviceKey);
            if (lruItem == null) {
                /**
                 * LinkedHashMap
                 *      a、accessOrder:ture=访问顺序排序(get/put时排序)/ACCESS-LAST;false=插入顺序排期/FIFO;
                 *      b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法;
                 */
                lruItem = new LinkedHashMap<String, String>(16, 0.75f, true){
                    @Override
                    protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
                        if(super.size() > 3){
                            return true;
                        }else{
                            return false;
                        }
                    }
                };
                jobLRUMap.putIfAbsent(serviceKey, lruItem);
            }
    
            // put
            for (String address: addressSet) {
                if (!lruItem.containsKey(address)) {
                    lruItem.put(address, address);
                }
            }
    
            // load
            String eldestKey = lruItem.entrySet().iterator().next().getKey();
            String eldestValue = lruItem.get(eldestKey);//LRU算法关键体现在这里,实现了固定长度的LRU算法
            return eldestValue;
        }

    方案四:LFU(访问最频繁的使用概率也最高),因此,将使用最频繁的放在最后面使用,保证了使用不频繁的也能使用上

    hashmap的存放是无序的。

    public String doRoute(String serviceKey, TreeSet<String> addressSet) {
    
            // cache clear
            if (System.currentTimeMillis() > CACHE_VALID_TIME) {
                jobLfuMap.clear();
                CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
            }
    
            // lfu item init
            HashMap<String, Integer> lfuItemMap = jobLfuMap.get(serviceKey);     // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList;
            if (lfuItemMap == null) {
                lfuItemMap = new HashMap<String, Integer>();
                jobLfuMap.putIfAbsent(serviceKey, lfuItemMap);   // 避免重复覆盖
            }
            for (String address: addressSet) {
                if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) >1000000 ) {
                    lfuItemMap.put(address, 0);
                }
            }
    //        System.out.println(lfuItemMap);
    
            // load least userd count address
            List<Map.Entry<String, Integer>> lfuItemList = new ArrayList<Map.Entry<String, Integer>>(lfuItemMap.entrySet());
            Collections.sort(lfuItemList, new Comparator<Map.Entry<String, Integer>>() {
                @Override
                public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                    return o1.getValue().compareTo(o2.getValue());
                }
            });
            System.out.println(lfuItemList);
    
            Map.Entry<String, Integer> addressItem = lfuItemList.get(0);
            String minAddress = addressItem.getKey();
            addressItem.setValue(addressItem.getValue() + 1);
    
            return minAddress;
    //        return null;
        }

    方案五:一致性哈希

    consistent hashing 是一种 hash 算法,简单的说,在移除 / 添加一个 cache 时,它能够尽可能小的改变已存在 key 映射关系,尽可能的满足单调性的要求。

    1. 每个节点设置5个虚拟节点

    2. 计算serviceKey的hash值

    3. 使用treeMap的tailMap方法返回其键大于或等于fromKey的部分视图

    4. 取视图的第一个作为服务调用的address

    private int VIRTUAL_NODE_NUM = 5;
    
        /**
         * get hash code on 2^32 ring (md5散列的方式计算hash值)
         * @param key
         * @return
         */
        private long hash(String key) {
    
            // md5 byte
            MessageDigest md5;
            try {
                md5 = MessageDigest.getInstance("MD5");
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException("MD5 not supported", e);
            }
            md5.reset();
            byte[] keyBytes = null;
            try {
                keyBytes = key.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("Unknown string :" + key, e);
            }
    
            md5.update(keyBytes);
            byte[] digest = md5.digest();
    
            // hash code, Truncate to 32-bits
            long hashCode = ((long) (digest[3] & 0xFF) << 24)
                    | ((long) (digest[2] & 0xFF) << 16)
                    | ((long) (digest[1] & 0xFF) << 8)
                    | (digest[0] & 0xFF);
    
            long truncateHashCode = hashCode & 0xffffffffL;
            return truncateHashCode;
        }
    
        public String doRoute(String serviceKey, TreeSet<String> addressSet) {
    
            // ------A1------A2-------A3------
            // -----------J1------------------
            TreeMap<Long, String> addressRing = new TreeMap<Long, String>();
            for (String address: addressSet) {
                for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
                    long addressHash = hash("SHARD-" + address + "-NODE-" + i);
                    addressRing.put(addressHash, address);
                }
            }
            //TreeMap的存放是根据addressHash值排序
    
    
            long jobHash = hash(serviceKey);
            SortedMap<Long, String> lastRing = addressRing.tailMap(jobHash);
            //将addressHash值大于jobHash值的adress都取出来
    //        System.out.println(lastRing);
            if (!lastRing.isEmpty()) {
                //如果这个地址不为空,就返回这个的第一个
                return lastRing.get(lastRing.firstKey());
            }
    //        System.out.println(lastRing.firstKey());
            //返回没有减少的地址的第一个
            return addressRing.firstEntry().getValue();
        }
  • 相关阅读:
    城市的划入划出效果
    文本溢出省略解决笔记css
    长串英文数字强制折行解决办法css
    Poj 2352 Star
    树状数组(Binary Indexed Trees,二分索引树)
    二叉树的层次遍历
    Uva 107 The Cat in the Hat
    Uva 10336 Rank the Languages
    Uva 536 Tree Recovery
    Uva10701 Pre, in and post
  • 原文地址:https://www.cnblogs.com/lovejune/p/12464752.html
Copyright © 2011-2022 走看看