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) {

    }
}