Ribbon源码学习(二)

201 阅读2分钟

一.前文回顾

上一次,:Ribbon源码学习(一) 讨论到LoadBalancerClient.execute,是真正的发送Http请求的类。

OK, 现在开始继续分析LoadBalancerClient

我们可以看到,这个LoadBalancerClient 是个接口

那么我们直接看到对应的实现即可。

分析之前,先铺垫一下知识,我们知道Ribbon的功能就是可以做到服务的负载均衡,权重,随机等调用方法。
然后通过RibbonLoadBalancerClient 服务A发给服务B的http请求进行了封装,走以上的调用策略。

那么,就开始分析RibbonLoadBalancerClient.execute


二.RibbonLoadBalancerClient源码分析

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
  	
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
         
         	// 通过策略选择正确的server
		Server server = getServer(loadBalancer, hint);
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}
		RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
				serviceId), serverIntrospector(serviceId).getMetadata(server));

		return execute(serviceId, ribbonServer, request);
	}

以上我们可以看到

Server server = getServer(loadBalancer, hint);

上面的代码就是获取到对应的server(也就是真正要调用的服务对象)

你可能会问我,那么server到底又是什么呢?

下面放一张Server 对象的截图

从截图中就可以看到,无非是一些服务的信息属性。
比如port端口, id服务名, appName应用名, appServerGroup app应用组别等等。

在拿到这个server对象之后,就是一波远程调用。
在这里我们可以发现,getServer() 就是ribbon策略的关键,是轮训,随机,权重等等。
事不宜迟,直接进入getServer() 方法。

getServer(ILoadBalancer loadBalancer, Object hint)

	protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
		if (loadBalancer == null) {
			return null;
		}
		// Use 'default' on a null hint, or just pass it on?
		return loadBalancer.chooseServer(hint != null ? hint : "default");
	}

之后就是loadBalancer.chooseServer(hint != null ? hint : "default")

顾名思义,选择对应的Server,到这里应该是非常接近真相了。

	 protected IRule rule = DEFAULT_RULE;
     
     DEFAULE_RULE = new RoundRobinRule();

    public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
            	// 通过rule选择对应的策略
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }

所以我们看到这个rule, 默认的就是RoundRobinRule 轮训的rule.
我们只需要去观察RoundRobinRule类的rule.choose(key) 就够用了

三.RoundRobinRule源码分析

 public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            log.warn("no load balancer");
            return null;
        }

        Server server = null;
        int count = 0;
        while (server == null && count++ < 10) {
            List<Server> reachableServers = lb.getReachableServers();
            List<Server> allServers = lb.getAllServers();
            int upCount = reachableServers.size();
            int serverCount = allServers.size();

            if ((upCount == 0) || (serverCount == 0)) {
                log.warn("No up servers available from load balancer: " + lb);
                return null;
            }

		// 这里维护着server遍历的下标
            int nextServerIndex = incrementAndGetModulo(serverCount);
             
             // allServers就是所有server的集合
            server = allServers.get(nextServerIndex);

            if (server == null) {
                /* Transient. */
                Thread.yield();
                continue;
            }

            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }

            // Next.
            server = null;
        }

        if (count >= 10) {
            log.warn("No available alive servers after 10 tries from load balancer: "
                    + lb);
        }
        return server;
    }

这个就很简单了,简单的轮询算法。然后轮询对应的server即可。
轮询算法无非就是维护了一个nextServerIndex索引(记录轮训的下标), servers就是一个服务器的集合。

四.流程图