简析Ribbon源码

  本篇不纠结源码细节,源码走读可以参看Spring Cloud源码分析(二)Ribbon深入理解Ribbon之源码解析。Ribbon这一块源码的设计模式非常值得借鉴学习,符合开闭原则,对扩展开放,对修改封闭。所以大致看下源码这块的程序设计的思路,看Ribbon怎么把各个功能整合在一起的。
  首先从Ribbon中一个非常重要的组件LoadBalancerClient开始:

public interface LoadBalancerClient extends ServiceInstanceChooser {

   <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

   <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

   URI reconstructURI(ServiceInstance instance, URI original);
}

  execute方法会使用从LoadBalancer获取的ServiceInstance执行请求。LoadBalancerClient是一个接口,它继承ServiceInstanceChooser:

public interface ServiceInstanceChooser {
    ServiceInstance choose(String serviceId);
}

  ServiceInstanceChooser接口,只有一个方法,用来根据serviceId来获取ServiceInstance。

  来看LoadBalancerClient的实现类RibbonLoadBalancerClient,看重要的部分:

public class RibbonLoadBalancerClient implements LoadBalancerClient {

    //...略

	@Override
	public ServiceInstance choose(String serviceId) {
		Server server = getServer(serviceId);
		if (server == null) {
			return null;
		}
		return new RibbonServer(serviceId, server, isSecure(server, serviceId),
				serverIntrospector(serviceId).getMetadata(server));
	}

	@Override
	public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
		ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
		Server server = getServer(loadBalancer);
		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);
	}

	protected Server getServer(String serviceId) {
		return getServer(getLoadBalancer(serviceId));
	}

	protected Server getServer(ILoadBalancer loadBalancer) {
		if (loadBalancer == null) {
			return null;
		}
		return loadBalancer.chooseServer("default"); // TODO: better handling of key
	}

	protected ILoadBalancer getLoadBalancer(String serviceId) {
		return this.clientFactory.getLoadBalancer(serviceId);
	}

    //...略

}

  作为负载均衡的客户端,RibbonLoadBalancerClient的execute()方法先找到ILoadBalancer,然后ILoadBalancer选择出服务实例,最后用找到的实例去进行请求。

  来看ILoadBalancer,ILoadBalancer是实现软件负载均衡的一个接口:

public interface ILoadBalancer {
	public void addServers(List<Server> newServers);
	public Server chooseServer(Object key);
	public void markServerDown(Server server);
    public List<Server> getReachableServers();
	public List<Server> getAllServers();
}

  它提供可供选择的服务注册列表信息。到这里要思考下,既然有了ILoadBalancer,那么还需要有负载均衡策略来决定某次请求的服务实例,还要检查服务实例是否有效。因此ILoadBalancer的子类BaseLoadBalancer来实现这些,当然不止这些。

public class BaseLoadBalancer extends AbstractLoadBalancer implements
        PrimeConnections.PrimeConnectionListener, IClientConfigAware {

    //...略

    protected IRule rule = DEFAULT_RULE;
    protected IPingStrategy pingStrategy = DEFAULT_PING_STRATEGY;
    protected IPing ping = null;

    // 实例化方式
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        String ruleClassName = (String) clientConfig
                .getProperty(CommonClientConfigKey.NFLoadBalancerRuleClassName);
        String pingClassName = (String) clientConfig
                .getProperty(CommonClientConfigKey.NFLoadBalancerPingClassName);

        IRule rule;
        IPing ping;
        try {
            rule = (IRule) ClientFactory.instantiateInstanceWithClientConfig(
                    ruleClassName, clientConfig);
            ping = (IPing) ClientFactory.instantiateInstanceWithClientConfig(
                    pingClassName, clientConfig);
        } catch (Exception e) {
            throw new RuntimeException("Error initializing load balancer", e);
        }
        initWithConfig(clientConfig, rule, ping);
    }

    /* Returns either null, or "server:port/servlet" */
    public String choose(Object key) {
        if (rule == null) {
            return null;
        } else {
            try {
                Server svr = rule.choose(key);
                return ((svr == null) ? null : svr.getId());
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server", name, e);
                return null;
            }
        }
    }
}

  可以看到类属性IRule、IPing。IRule决定了按照什么策略去选择服务实例,IPing决定了怎么判断服务可用。看下IRule:

public interface IRule{
    public Server choose(Object key); 
    public void setLoadBalancer(ILoadBalancer lb);
    public ILoadBalancer getLoadBalancer();    
}
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {

    private ILoadBalancer lb;
        
    @Override
    public void setLoadBalancer(ILoadBalancer lb){
        this.lb = lb;
    }
    
    @Override
    public ILoadBalancer getLoadBalancer(){
        return lb;
    }      
}

  IRule有很多实现类,默认是RoundRobinRule。IRule拥有ILoadBalancer属性,以便IRule拿到所有的可用Server。
  IPing是用来来判断该server是否有响应,从而判断该server是否可用。

  在BaseLoadBalancer 的子类DynamicServerListLoadBalancer这个扩展类中添加了ServerList、ServerListFilter,以获取所有的服务实例和添加过滤策略。
  ServerList是获取所有的server信息的接口:

public interface ServerList<T extends Server> {
    public List<T> getInitialListOfServers();
    public List<T> getUpdatedListOfServers();   
}

  ServerListFilter接口用于过滤某些server列表:

public interface ServerListFilter<T extends Server> {
    public List<T> getFilteredListOfServers(List<T> servers);
}

  从Eureka获取server时,ServerList的实现类为DiscoveryEnabledNIWSServerList。

猜你喜欢

转载自blog.csdn.net/zero__007/article/details/83932289