Ribbon的初始化源码

DyamicServerListLoadBalancer的构造方法中,当接收到的参数为IClientConfig的时候,会直接调用initWithNiwsConfig()方法开始根据配置类开始进行初始化。

首先会调用父类BaseLoaderBalancer的initWithNiwsConfig()方法。

在BaseLoaderBalancer这里首先会在配置类中寻找相应的IPing和IRule并获取这两个类相应的实例,而后在initWithConfig()方法中对这两者以及相关属性进行更详细的配置。

void initWithConfig(IClientConfig clientConfig, IRule rule, IPing ping) {
    this.config = clientConfig;
    String clientName = clientConfig.getClientName();
    this.name = clientName;
    int pingIntervalTime = Integer.parseInt(""
            + clientConfig.getProperty(
                    CommonClientConfigKey.NFLoadBalancerPingInterval,
                    Integer.parseInt("30")));
    int maxTotalPingTime = Integer.parseInt(""
            + clientConfig.getProperty(
                    CommonClientConfigKey.NFLoadBalancerMaxTotalPingTime,
                    Integer.parseInt("2")));

    setPingInterval(pingIntervalTime);
    setMaxTotalPingTime(maxTotalPingTime);

    // cross associate with each other
    // i.e. Rule,Ping meet your container LB
    // LB, these are your Ping and Rule guys ...
    setRule(rule);
    setPing(ping);
    setLoadBalancerStats(new LoadBalancerStats(clientName));
    rule.setLoadBalancer(this);
    if (ping instanceof AbstractLoadBalancerPing) {
        ((AbstractLoadBalancerPing) ping).setLoadBalancer(this);
    }
    logger.info("Client:" + name + " instantiated a LoadBalancer:"
            + toString());
    boolean enablePrimeConnections = clientConfig.get(
            CommonClientConfigKey.EnablePrimeConnections, DefaultClientConfigImpl.DEFAULT_ENABLE_PRIME_CONNECTIONS);

    if (enablePrimeConnections) {
        this.setEnablePrimingConnections(true);
        PrimeConnections primeConnections = new PrimeConnections(
                this.getName(), clientConfig);
        this.setPrimeConnections(primeConnections);
    }
    init();

}

先在配置类中读取ping操作的间隔,默认30秒。然后在setPingInterval()方法中将这一参数正式用到。在setPingInterval()方法中,会调用setupPingTask()方法正式根据时间间隔创建定时任务PingTask来不断间隔一定时间去对所有地址进行ping检查。

private void setupPingTask() {
    if (canSkipPing()) {
        return;
    }
    if (lbTimer != null) {
        lbTimer.cancel();
    }
    lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name,
            true);
    lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000);
    forceQuickPing();
}

class PingTask extends TimerTask {
    public void run() {
        Pinger ping = new Pinger();
        try {
            ping.runPinger();
        } catch (Throwable t) {
            logger.error("Throwable caught while running extends for "
                    + name, t);
        }
    }
}

public void runPinger() {

    if (pingInProgress.get()) {
        return; // Ping in progress - nothing to do
    } else {
        pingInProgress.set(true);
    }

    // we are "in" - we get to Ping

    Object[] allServers = null;
    boolean[] results = null;

    Lock allLock = null;
    Lock upLock = null;

    try {
        /*
         * The readLock should be free unless an addServer operation is
         * going on...
         */
        allLock = allServerLock.readLock();
        allLock.lock();
        allServers = allServerList.toArray();
        allLock.unlock();

        int numCandidates = allServers.length;
        results = new boolean[numCandidates];

        if (logger.isDebugEnabled()) {
            logger.debug("LoadBalancer:  PingTask executing ["
                    + numCandidates + "] servers configured");
        }

        for (int i = 0; i < numCandidates; i++) {
            results[i] = false; /* Default answer is DEAD. */
            try {
                // NOTE: IFF we were doing a real ping
                // assuming we had a large set of servers (say 15)
                // the logic below will run them serially
                // hence taking 15 times the amount of time it takes
                // to ping each server
                // A better method would be to put this in an executor
                // pool
                // But, at the time of this writing, we dont REALLY
                // use a Real Ping (its mostly in memory eureka call)
                // hence we can afford to simplify this design and run
                // this
                // serially
                if (ping != null) {
                    results[i] = ping.isAlive((Server) allServers[i]);
                }
            } catch (Throwable t) {
                logger.error("Exception while pinging Server:"
                        + allServers[i], t);
            }
        }

        final List<Server> newUpList = new ArrayList<Server>();
        final List<Server> changedServers = new ArrayList<Server>();

        for (int i = 0; i < numCandidates; i++) {
            boolean isAlive = results[i];
            Server svr = (Server) allServers[i];
            boolean oldIsAlive = svr.isAlive();

            svr.setAlive(isAlive);

            if (oldIsAlive != isAlive) {
                changedServers.add(svr);
                if (logger.isDebugEnabled()) {
                    logger.debug("LoadBalancer:  Server [" + svr.getId()
                            + "] status changed to "
                            + (isAlive ? "ALIVE" : "DEAD"));
                }
            }

            if (isAlive) {
                newUpList.add(svr);
            }
        }
        // System.out.println(count + " servers alive");
        upLock = upServerLock.writeLock();
        upLock.lock();
        upServerList = newUpList;
        upLock.unlock();

        notifyServerStatusChangeListener(changedServers);

    } catch (Throwable t) {
        logger.error("Throwable caught while running the Pinger-"
                + name, t);
    } finally {
        pingInProgress.set(false);
    }
}

 

在ping检查中,最后调用到的是Pinger的runPinger()方法。

 

为了保证这一操作的线程安全,通过信号量的形式保证这一操作在某一时间的唯一性。

而后会获取所有当前所有的服务器数组,遍历数组去依次进行ping确认其状态是否可用,如果新的状态与之前的状态发生改变,那么就将其存入存放状态发生改变的服务器数组,并且如果其状态为可用,则加入可用服务器数组并更新。

而后通知所有状态改变监听器公告所有发生状态改变的服务器。

如果采用了PingUrl会直接构造url对相应的服务器进行请求来判断该服务器是否可用。

 

该任务的定时调用间隔时间就是配置的ping间隔时间。

 

之后回到DyamicServerListLoadBalancer的initWithNiwConfig()方法,会配置服务器列表和服务器过滤器。

而后调用restOfInit()方法,并在其中调用updateListOfServers()方法更新服务器列表。

public void updateListOfServers() {
    List<T> servers = new ArrayList<T>();
    if (serverListImpl != null) {
        servers = serverListImpl.getUpdatedListOfServers();
        LOGGER.debug("List of Servers for {} obtained from Discovery client: {}",
                getIdentifier(), servers);

        if (filter != null) {
            servers = filter.getFilteredListOfServers(servers);
            LOGGER.debug("Filtered List of Servers for {} obtained from Discovery client: {}",
                    getIdentifier(), servers);
        }
    }
    lastUpdated.set(System.currentTimeMillis());
    updateAllServerList(servers);
}

这里会根据之前得到的服务器列表类来获取服务器列表。

如果是默认的ConfigurationBasedServerList,则会直接读配置类中的服务器列表并返回。

而如果采用了DiscoveryEnabledNIWSServerList,则向eureka-client获得相应的服务器列表。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值