zoukankan      html  css  js  c++  java
  • 【微服务】SpringCloud Ribbon 负载均衡随机访问算法

    github 解析源码:https://github.com/Netflix/ribbon/blob/master/ribbonloadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java

    1.Ribbon 负载均衡算法架构图

    总结:可以看出Ribbon架构采用的都是基于一个接口提供规范,抽象类实现基础功能,子类继承抽象类 实现自己特有的算法。而常见的java 中间件常用框架都是采用类似的思想进行框架的设计。

    2.随机算法代码解析

    package com.hblg.myrule;
    
    import com.netflix.client.config.IClientConfig;
    import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    import com.netflix.loadbalancer.ILoadBalancer;
    import com.netflix.loadbalancer.Server;
    
    import java.util.List;
    import java.util.concurrent.ThreadLocalRandom;
    
    /**
     * @author i
     * @create 2020/2/19 17:46
     * @Description  RandomRule Ribbon随机访问算法
     */
    //继承第二阶梯的抽象类
    public class RandomRule extends AbstractLoadBalancerRule {
    
        /**
         * Randomly choose from all living servers
         */
        public Server choose(ILoadBalancer lb, Object key) {
            //先判断负载均衡是否为空 为空直接返回
            if (lb == null) {
                return null;
            }
            Server server = null;
    
            //使用while 而不是用if 为的是在server==null 在进行依次判断 避免因多线程操作server数据的线程安全问题
            while (server == null) {
                //如果当前线程是中断状态 直接返回
                if (Thread.interrupted()) {
                    return null;
                }
                //获取到在线微服务列表
                List<Server> upList = lb.getReachableServers();
                //获取到所有包含在线和可能因网络拥堵出现的异常服务列表
                List<Server> allList = lb.getAllServers();
                //获取到所有的服务的数量
                int serverCount = allList.size();
                //如果数量为0 直接返回null
                if (serverCount == 0) {
                    /*
                     * No servers. End regardless of pass, because subsequent passes
                     * only get more restrictive.
                     */
                    return null;
                }
                //根据当前服务列表数量 随机生成一个生产者节点下标
                int index = chooseRandomInt(serverCount);
                server = upList.get(index);
    
                //如果当前server节点为null 当前线程让步 继续下一次
                if (server == null) {
                    /*
                     * The only time this should happen is if the server list were
                     * somehow trimmed. This is a transient condition. Retry after
                     * yielding.
                     */
                    Thread.yield();
                    continue;
                }
    
                //如果当前Server节点 是活跃状态直接返回 使用
                if (server.isAlive()) {
                    return (server);
                }
                //为了避免其他情况的出现 设置当前Server节点为null 线程让步 
                // Shouldn't actually happen.. but must be transient or a bug.
                server = null;
                Thread.yield();
            }
    
            return server;
    
        }
    
        /***
         * ThreadLocalRandom用内部生成的种子进行初始化,可能不会被修改。
         * 适用时,在并发程序中使用ThreadLocalRandom而不是共享的Random对象通常会遇到更少的开销和争用。
         * 当多个任务(例如,每个ForkJoinTask )在线程池中并行使用随机数时,使用ThreadLocalRandom是特别合适的。
         * @param serverCount
         * @return
         */
        protected int chooseRandomInt(int serverCount) {
            return ThreadLocalRandom.current().nextInt(serverCount);
        }
    
        @Override
        public Server choose(Object key) {
            return choose(getLoadBalancer(), key);
        }
    
        @Override
        public void initWithNiwsConfig(IClientConfig iClientConfig) {
    
        }
    }
    
  • 相关阅读:
    python活力练习Day13
    检测一个字符串在另外一个字符串中的位置
    Python活力练习Day12
    Python多进程与单进程效率对比
    HTML-Note
    Python判断自定义的参数格式是否正确
    图片的灰与彩
    Git常用命令
    Linux 单引号和双引号的区别
    类函数中获取进程池对象的地址
  • 原文地址:https://www.cnblogs.com/qxlxi/p/12860734.html
Copyright © 2011-2022 走看看