springcloud Ribbon详解

微服务间的调用,网关请求转发,feign都是通过ribbon实现的,因此学习ribbon的原理还是很重要的,而ribbon的作用是用于负载均衡,springcloud自动化整合配置ribbon是RibbonEurekaAutoConfiguration这个类。对于开发者来说,使用ribbon只需要在RestTemplate上添加@LoadBalanced注解即可实现消费方的负载均衡

RestTemplate

resttemplate用于不同服务间的通信和访问,主要有发送GET,POST,PUT,DELETE(*ForEntity方法访问另一个服务的提供的接口返回需要的结果)

开头我们提到在RestTemplate上添加@LoadBalancer注解即可实现负载均衡,通过源码我们可以知道实现的原理。

ribbon源码

1.原理

我们可以找到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);
}

该接口为客户端负载均衡的接口,我们可以找到客户端的自动配置类LoadBalancerAutoConfiguration类


@ConditionalOnClass({RestTemplate.class}) //实现自动化配置 resttemplate类需存在于当前工程中
@ConditionalOnBean({LoadBalancerClient.class}) //实现自动化配置 LoadBalancerClient类的实现bean 需存在于当前工程中
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
	    @LoadBalanced
	    @Autowired(
	        required = false
	    )
	    private List<RestTemplate> restTemplates = Collections.emptyList();//创建空的集合存放RestTemplate进行初始化
	
		@Bean
	    public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
	        return () -> {
	            restTemplateCustomizers.ifAvailable((customizers) -> {
	                Iterator var2 = this.restTemplates.iterator();
	
	                while(var2.hasNext()) {
	                    RestTemplate restTemplate = (RestTemplate)var2.next();
	                    Iterator var4 = customizers.iterator();
	
	                    while(var4.hasNext()) {
	                        RestTemplateCustomizer customizer = (RestTemplateCustomizer)var4.next();
	                        customizer.customize(restTemplate); //消费RestTemplate,具体消费方法在下面
	                    }
	                }
	
	            });
	        };
	    }
	    
	    @ConditionalOnClass({RetryTemplate.class}) //假如工程中使用的是RetryTemplate的实现bean则使用该消费方法
	    public static class RetryInterceptorAutoConfiguration {
	        public RetryInterceptorAutoConfiguration() {
	        }
	
	        @Bean //注入RetryLoadBalancerInterceptor bean 用于消费(对请求进行拦截)
	        @ConditionalOnMissingBean
	        public RetryLoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties, LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory) {
	            return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, requestFactory, loadBalancedRetryFactory);
	        }
	
	        @Bean //具体消费方法
	        @ConditionalOnMissingBean
	        public RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
	            return (restTemplate) -> {
	                List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
	                list.add(loadBalancerInterceptor);
	                restTemplate.setInterceptors(list); //给restTemplate添加拦截器
	            };
	        }
	    }
	    
	    ...
    }

可以看出自动化配置类实现的原理是给被@LoadBalancer修饰的resttemplate对象发起请求时,对其进行拦截,负载均衡的是通过拦截器实现的,接下来我们看拦截器的具体实现:

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
    private LoadBalancerClient loadBalancer;
    private LoadBalancerRequestFactory requestFactory;

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
        this.loadBalancer = loadBalancer; //构造方法中传入了LoadBalancerClient负载均衡客户端接口
        this.requestFactory = requestFactory;
    }

    public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
        this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
    }

    public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        URI originalUri = request.getURI();
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        //根据服务名和端口获取到具体的url,调用客户端的execute方法进行拦截实现负载均衡 注意到 this.loadBalancer.execute(执行请求) 和this.requestFactory.createRequest(组装请求)方法 
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution)); 
    }
}
  • this.loadBalancer.execute(执行请求)

从intercept方法我们可以看出,最终还是调用LoadBalancerClient的execute方法,而LoadBalancerClient是一个接口,ribbon对其进行具体实现,实现的类是RibbonLoadBalancerClient,在该类中我们可以找到excute的实现方法:

    public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
        return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
    }

    public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
        ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId); //获取负载均衡器
        Server server = this.getServer(loadBalancer, hint); //负载均衡器中的choose方法选择出一个server执行request请求
        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); //将server对象转化为RibbonLoadBalancerClient定义的RibbonServer对象(存储了serviceId 服务id ,server ,secure https标识,metadata元数据)
            return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
        }
    }

    public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
        Server server = null;
        if (serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) {
            server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer();
        }

        if (server == null) {
            throw new IllegalStateException("No instances available for " + serviceId);
        } else {
            RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
            RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server); //服务追踪

            try {
                T returnVal = request.apply(serviceInstance); //根据选择出来的serviceInstance执行请求
                statsRecorder.recordStats(returnVal);
                return returnVal;
            } catch (IOException var8) {
                statsRecorder.recordStats(var8);
                throw var8;
            } catch (Exception var9) {
                statsRecorder.recordStats(var9);
                ReflectionUtils.rethrowRuntimeException(var9);
                return null;
            }
        }
    }

	//获取LoadBalancer负载均衡器
    protected ILoadBalancer getLoadBalancer(String serviceId) {
        return this.clientFactory.getLoadBalancer(serviceId);
    }

	//负载均衡器根据负载均衡策略挑选服务
    protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
        return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
    }
  • this.requestFactory.createRequest(组装请求)
    组装请求我们需要关注的重点是如何将逻辑服务名转化为具体的url的
public class LoadBalancerRequestFactory {
    private LoadBalancerClient loadBalancer;
    private List<LoadBalancerRequestTransformer> transformers;

    public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer, List<LoadBalancerRequestTransformer> transformers) {
        this.loadBalancer = loadBalancer;
        this.transformers = transformers;
    }

    public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer) {
        this.loadBalancer = loadBalancer;
    }

    public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) {
        return (instance) -> {
            HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer);
            LoadBalancerRequestTransformer transformer;
            if (this.transformers != null) {
                for(Iterator var6 = this.transformers.iterator(); var6.hasNext(); serviceRequest = transformer.transformRequest((HttpRequest)serviceRequest, instance)) {
                    transformer = (LoadBalancerRequestTransformer)var6.next();
                }
            }

            return execution.execute((HttpRequest)serviceRequest, body); //创建request最终调用的还是ClientHttpRequestExecution实现类的execute方法
        };
    }
}

接着看ClientHttpRequestExecution实现类InterceptingRequestExecution(该实现类在InterceptingClientHttpRequest类中):

class InterceptingClientHttpRequest extends AbstractBufferingClientHttpRequest {

		...
	    private class InterceptingRequestExecution implements ClientHttpRequestExecution {
	        private final Iterator<ClientHttpRequestInterceptor> iterator;
	
	        public InterceptingRequestExecution() {
	            this.iterator = InterceptingClientHttpRequest.this.interceptors.iterator();
	        }
	
	        public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
	            if (this.iterator.hasNext()) {
	                ClientHttpRequestInterceptor nextInterceptor = (ClientHttpRequestInterceptor)this.iterator.next();
	                return nextInterceptor.intercept(request, body, this);
	            } else {
	                HttpMethod method = request.getMethod();
	                Assert.state(method != null, "No standard HTTP method");
	                ClientHttpRequest delegate = InterceptingClientHttpRequest.this.requestFactory.createRequest(request.getURI(), method); //构建url ,注意到该request是由参数传进来的,调用的是ServiceRequestWrapper类getURI()方法
	                request.getHeaders().forEach((key, value) -> {
	                    delegate.getHeaders().addAll(key, value);
	                });
	                if (body.length > 0) {
	                    if (delegate instanceof StreamingHttpOutputMessage) {
	                        StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage)delegate;
	                        streamingOutputMessage.setBody((outputStream) -> {
	                            StreamUtils.copy(body, outputStream);
	                        });
	                    } else {
	                        StreamUtils.copy(body, delegate.getBody());
	                    }
	                }
	
	                return delegate.execute();
	            }
	        }
	    }
    }

接着看ServiceRequestWrapper类:

public class ServiceRequestWrapper extends HttpRequestWrapper {
    private final ServiceInstance instance;
    private final LoadBalancerClient loadBalancer;

    public ServiceRequestWrapper(HttpRequest request, ServiceInstance instance, LoadBalancerClient loadBalancer) {
        super(request);
        this.instance = instance;
        this.loadBalancer = loadBalancer;
    }

    public URI getURI() {
        URI uri = this.loadBalancer.reconstructURI(this.instance, this.getRequest().getURI()); //可以看到组装url最终调用的还是LoadBalancerClient 负载均衡客户端(RibbonLoadBalancerClient)的reconstructURI方法
        return uri;
    }
}

接着看RibbonLoadBalancerClient 的reconstructURI方法:

    public URI reconstructURI(ServiceInstance instance, URI original) {
        Assert.notNull(instance, "instance can not be null");
        String serviceId = instance.getServiceId();
        RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId); //SpringClientFactory类是一个用来创建客户端负载均衡器的工厂类,该工厂类回味每一个不同名的Ribbon客户端生成不同的context上下文(RibbonLoadBalancerContext存储负载均衡器的上下文和API操作,如reconstructURIWithServer)
        URI uri;
        Server server;
        if (instance instanceof RibbonLoadBalancerClient.RibbonServer) {
            RibbonLoadBalancerClient.RibbonServer ribbonServer = (RibbonLoadBalancerClient.RibbonServer)instance;
            server = ribbonServer.getServer();
            uri = RibbonUtils.updateToSecureConnectionIfNeeded(original, ribbonServer);
        } else {
            server = new Server(instance.getScheme(), instance.getHost(), instance.getPort());
            IClientConfig clientConfig = this.clientFactory.getClientConfig(serviceId);
            ServerIntrospector serverIntrospector = this.serverIntrospector(serviceId);
            uri = RibbonUtils.updateToSecureConnectionIfNeeded(original, clientConfig, serverIntrospector, server);
        }

        return context.reconstructURIWithServer(server, uri);
    }

继续看RibbonLoadBalancerContext 的reconstructURIWithServer方法:

    public URI reconstructURIWithServer(Server server, URI original) {
        String host = server.getHost(); //server中存放着服务的具体信息,如主机地址,端口等
        int port = server.getPort();
        String scheme = server.getScheme();
        
        if (host.equals(original.getHost()) 
                && port == original.getPort()
                && scheme == original.getScheme()) {
            return original;
        }
        if (scheme == null) {
            scheme = original.getScheme();
        }
        if (scheme == null) {
            scheme = deriveSchemeAndPortFromPartialUri(original).first();
        }

        try {
            StringBuilder sb = new StringBuilder();
            sb.append(scheme).append("://"); //前缀 如http ,https
            if (!Strings.isNullOrEmpty(original.getRawUserInfo())) {
                sb.append(original.getRawUserInfo()).append("@"); //
            }
            sb.append(host);  //主机地址 如127.0.0.1
            if (port >= 0) {
                sb.append(":").append(port); //端口
            }
            sb.append(original.getRawPath());
            if (!Strings.isNullOrEmpty(original.getRawQuery())) {
                sb.append("?").append(original.getRawQuery());
            }
            if (!Strings.isNullOrEmpty(original.getRawFragment())) {
                sb.append("#").append(original.getRawFragment());
            }
            URI newURI = new URI(sb.toString());
            return newURI;            
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

根据逻辑名找uri终于结束了…

现在我们回到负载均衡器
负载均衡客户端最终调用了负载均衡器的choose方法来选择一个server来执行请求,这也是ribbon的重点部分,如何选择出一个server

2.负载均衡器

springcloud Ribbon详解_第1张图片
ILoadBalancer

public interface ILoadBalancer {

	/**
	 * Initial list of servers.
	 * This API also serves to add additional ones at a later time
	 * The same logical server (host:port) could essentially be added multiple times
	 * (helpful in cases where you want to give more "weightage" perhaps ..)
	 * 
	 * @param newServers new servers to add
	 */
	public void addServers(List<Server> newServers); //添加servrer
	
	/**
	 * Choose a server from load balancer.
	 * 
	 * @param key An object that the load balancer may use to determine which server to return. null if 
	 *         the load balancer does not use this parameter.
	 * @return server chosen
	 */
	public Server chooseServer(Object key); //挑选出一个服务
	
	/**
	 * To be called by the clients of the load balancer to notify that a Server is down
	 * else, the LB will think its still Alive until the next Ping cycle - potentially
	 * (assuming that the LB Impl does a ping)
	 * 
	 * @param server Server to mark as down
	 */
	public void markServerDown(Server server); //下线服务
	
	/**
	 * @deprecated 2016-01-20 This method is deprecated in favor of the
	 * cleaner {@link #getReachableServers} (equivalent to availableOnly=true)
	 * and {@link #getAllServers} API (equivalent to availableOnly=false).
	 *
	 * Get the current list of servers.
	 *
	 * @param availableOnly if true, only live and available servers should be returned
	 */
	@Deprecated
	public List<Server> getServerList(boolean availableOnly); //已不再使用

	/**
	 * @return Only the servers that are up and reachable.
     */
    public List<Server> getReachableServers(); //获取可用服务

    /**
     * @return All known servers, both reachable and unreachable.
     */
	public List<Server> getAllServers(); //获取所有服务
}

AbstractLoadBalancer:

public abstract class AbstractLoadBalancer implements ILoadBalancer {
    //定义了一个服务列表的枚举类型
    public enum ServerGroup{
        ALL,
        STATUS_UP,
        STATUS_NOT_UP        
    }
        
    /**
     * delegate to {@link #chooseServer(Object)} with parameter null.
     */
    public Server chooseServer() {
    	return chooseServer(null);
    }

    
    /**
     * List of servers that this Loadbalancer knows about
     * 
     * @param serverGroup Servers grouped by status, e.g., {@link ServerGroup#STATUS_UP}
     */
    public abstract List<Server> getServerList(ServerGroup serverGroup);
    
    /**
     * Obtain LoadBalancer related Statistics
     */
    public abstract LoadBalancerStats getLoadBalancerStats();    
}

BaseLoadBalancer:

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

	    private static Logger logger = LoggerFactory
	            .getLogger(BaseLoadBalancer.class);
	    private final static IRule DEFAULT_RULE = new RoundRobinRule(); //默认使用RoundRobinRule线性循环负载均衡策略
	    private final static SerialPingStrategy DEFAULT_PING_STRATEGY = new SerialPingStrategy(); //在构造方法中会直接启动一个定时检查server是否正常的任务(setipPingTask),间隔时间为10秒
	    private static final String DEFAULT_NAME = "default";
	    private static final String PREFIX = "LoadBalancer_";
	
	    protected IRule rule = DEFAULT_RULE;
	
	    protected IPingStrategy pingStrategy = DEFAULT_PING_STRATEGY;
	
	    protected IPing ping = null;
	
	    @Monitor(name = PREFIX + "AllServerList", type = DataSourceType.INFORMATIONAL)
	    protected volatile List<Server> allServerList = Collections
	            .synchronizedList(new ArrayList<Server>()); //存放所有服务实例
	    @Monitor(name = PREFIX + "UpServerList", type = DataSourceType.INFORMATIONAL)
	    protected volatile List<Server> upServerList = Collections
	            .synchronizedList(new ArrayList<Server>()); //存放正常启动服务实例
	            
	    @Override
	    public void addServers(List<Server> newServers) {
	        if (newServers != null && newServers.size() > 0) {
	            try {
	                ArrayList<Server> newList = new ArrayList<Server>();
	                newList.addAll(allServerList);
	                newList.addAll(newServers);
	                setServersList(newList);
	            } catch (Exception e) {
	                logger.error("LoadBalancer [{}]: Exception while adding Servers", name, e);
	            }
	        }
	    }
	    
	    //choose方法,最终执行负载均衡策略的choose方法
	    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;
	            }
	        }
	    }

	    private static class SerialPingStrategy implements IPingStrategy {
	
			//ping任务
	        @Override
	        public boolean[] pingServers(IPing ping, Server[] servers) {
	            int numCandidates = servers.length;
	            boolean[] results = new boolean[numCandidates];
	
	            logger.debug("LoadBalancer:  PingTask executing [{}] servers configured", numCandidates);
				//线性循环遍历
	            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(servers[i]);
	                    }
	                } catch (Exception e) {
	                    logger.error("Exception while pinging Server: '{}'", servers[i], e);
	                }
	            }
	            return results;
	        }
	    }
	    
    	public void markServerDown(Server server) {
        if (server == null || !server.isAlive()) {
            return;
        }

        logger.error("LoadBalancer [{}]:  markServerDown called on [{}]", name, server.getId());
        server.setAlive(false); //下线服务
        // forceQuickPing();

        notifyServerStatusChangeListener(singleton(server)); //更新监听器状态
    }
	
	    private void notifyServerStatusChangeListener(final Collection<Server> changedServers) {
        if (changedServers != null && !changedServers.isEmpty() && !serverStatusListeners.isEmpty()) {
            for (ServerStatusChangeListener listener : serverStatusListeners) {
                try {
                    listener.serverStatusChanged(changedServers); //更新监听器状态
                } catch (Exception e) {
                    logger.error("LoadBalancer [{}]: Error invoking server status change listener", name, e);
                }
            }
        }
    }
	
		...
	}

DynamicServerListLoadBalancer(在运行期能修改服务列表):

  • ServerList(存储服务实例的对象)
volatile ServerList<T> serverListImpl; //服务列表的操作对象(获取动态的服务列表)

public interface ServerList<T extends Server> {

    public List<T> getInitialListOfServers();
    
    /**
     * Return updated list of servers. This is called say every 30 secs
     * (configurable) by the Loadbalancer's Ping cycle
     * 
     */
    public List<T> getUpdatedListOfServers();   

}

spring整合 eureka和ribbon的配置类EurekaRibbonClientConfiguration中可以找到ServerList接口的使用的实现类DiscoveryEnabledNIWSServeerList

    @Bean
    @ConditionalOnMissingBean
    public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
        if (this.propertiesFactory.isSet(ServerList.class, this.serviceId)) {
            return (ServerList)this.propertiesFactory.get(ServerList.class, config, this.serviceId);
        } else {
            DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(config, eurekaClientProvider); //列表对象使用的是DiscoveryEnabledNIWSServerList
            DomainExtractingServerList serverList = new DomainExtractingServerList(discoveryServerList, config, this.approximateZoneFromHostname);
            return serverList;
        }
    }

接下来看DiscoveryEnabledNIWSServerList的对接口的具体实现方法

 public List<DiscoveryEnabledServer> getInitialListOfServers() {
        return this.obtainServersViaDiscovery();
    }

    public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
        return this.obtainServersViaDiscovery();
    }

    private List<DiscoveryEnabledServer> obtainServersViaDiscovery() {
        List<DiscoveryEnabledServer> serverList = new ArrayList();
        if (this.eurekaClientProvider != null && this.eurekaClientProvider.get() != null) {
            EurekaClient eurekaClient = (EurekaClient)this.eurekaClientProvider.get();
            if (this.vipAddresses != null) {
                String[] var3 = this.vipAddresses.split(",");
                int var4 = var3.length;

                for(int var5 = 0; var5 < var4; ++var5) {
                    String vipAddress = var3[var5];
                    List<InstanceInfo> listOfInstanceInfo = eurekaClient.getInstancesByVipAddress(vipAddress, this.isSecure, this.targetRegion); //vipAddresses 逻辑上的服务名 返回实例对象
                    Iterator var8 = listOfInstanceInfo.iterator();

                    while(var8.hasNext()) {
                        InstanceInfo ii = (InstanceInfo)var8.next();
                        if (ii.getStatus().equals(InstanceStatus.UP)) { //遍历出正常服务的列表返回
                            if (this.shouldUseOverridePort) {
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Overriding port on client name: " + this.clientName + " to " + this.overridePort);
                                }

                                InstanceInfo copy = new InstanceInfo(ii);
                                if (this.isSecure) {
                                    ii = (new Builder(copy)).setSecurePort(this.overridePort).build();
                                } else {
                                    ii = (new Builder(copy)).setPort(this.overridePort).build();
                                }
                            }

                            DiscoveryEnabledServer des = this.createServer(ii, this.isSecure, this.shouldUseIpAddr);
                            serverList.add(des);
                        }
                    }

                    if (serverList.size() > 0 && this.prioritizeVipAddressBasedServers) {
                        break;
                    }
                }
            }

            return serverList;
        } else {
            logger.warn("EurekaClient has not been initialized yet, returning an empty list");
            return new ArrayList();
        }
    }
  • ServerListUpdater(动态更新服务实例列表)
    该负载均衡器启动了一个定时任务,动态更新服务实例列表
    protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
    	//重写了doUpdate方法
        @Override
        public void doUpdate() {
            updateListOfServers();
        }
    };
    
    @VisibleForTesting
    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);
            }
        }
        updateAllServerList(servers);
    }
    
    protected void updateAllServerList(List<T> ls) {
        // other threads might be doing this - in which case, we pass
        if (serverListUpdateInProgress.compareAndSet(false, true)) {
            try {
                for (T s : ls) {
                    s.setAlive(true); // set so that clients can start using these
                                      // servers right away instead
                                      // of having to wait out the ping cycle.
                }
                setServersList(ls);
                super.forceQuickPing();
            } finally {
                serverListUpdateInProgress.set(false);
            }
        }
    }

这个方法写法很特别,首先先看ServerListUpdater这个接口,它内部定义了其他接口和抽象方法,ServerListUpdater.UpdateAction updateAction 作为对象,new ServerListUpdater.UpdateAction() { …}是匿名实现类

public interface ServerListUpdater {

	//外部接口中定义了一个内部接口,内部接口定义了抽象方法
    public interface UpdateAction {
        void doUpdate();
    }

	//外部接口定义的抽象方法,内部接口作为参数传入,实现类定义了一个定时任务,执行内容为doupdate方法的实现逻辑
    void start(UpdateAction updateAction);
		
	...

}

在DynamicServerListLoadBalancer的构造方法中创建了一个该接口实现类PollingServerListUpdater对象,该实现类重写了start方法,启动了一个定时任务,执行doupdate()方法

    public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping, 
            ServerList<T> serverList, ServerListFilter<T> filter) {
        this(
                clientConfig,
                rule,
                ping,
                serverList,
                filter,
                new PollingServerListUpdater()
        );
    }

接下来看PollingServerListUpdater中的start方法


    private static long LISTOFSERVERS_CACHE_UPDATE_DELAY = 1000; // msecs;
    private static int LISTOFSERVERS_CACHE_REPEAT_INTERVAL = 30 * 1000; // msecs;
    @Override
    public synchronized void start(final UpdateAction updateAction) {
        if (isActive.compareAndSet(false, true)) {
            final Runnable wrapperRunnable = new Runnable() {
                @Override
                public void run() {
                    if (!isActive.get()) {
                        if (scheduledFuture != null) {
                            scheduledFuture.cancel(true);
                        }
                        return;
                    }
                    try {
                        updateAction.doUpdate();
                        lastUpdated = System.currentTimeMillis();
                    } catch (Exception e) {
                        logger.warn("Failed one update cycle", e);
                    }
                }
            };

            scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
                    wrapperRunnable,
                    initialDelayMs, // =LISTOFSERVERS_CACHE_UPDATE_DELAY 
                    refreshIntervalMs, // =LISTOFSERVERS_CACHE_REPEAT_INTERVAL 
                    TimeUnit.MILLISECONDS
            );
        } else {
            logger.info("Already active, no-op");
        }
    }

也就是,更新服务实例在初始化后延迟1秒执行,以30秒为周期重复执行

在执行doUpdate定时任务时,可以看到filter对象,该对象会对获取到的服务列表进行过滤操作。

  • ServerListFilter接口

springcloud Ribbon详解_第2张图片

  • AbstractServerListFilter :定义了存储负载均衡器的属性和统计信息的对象LoadBalancerStats
public abstract class AbstractServerListFilter<T extends Server> implements ServerListFilter<T> {

    private volatile LoadBalancerStats stats;
    
    public void setLoadBalancerStats(LoadBalancerStats stats) {
        this.stats = stats;
    }
    
    public LoadBalancerStats getLoadBalancerStats() {
        return stats;
    }

}
  • ZoneAffinityServerListFilter:(区域感知)会根据服务的实例所处的区域和消费者所处区域进行比较,过滤掉不是同一区域的服务实例
	//过滤
    @Override
    public List<T> getFilteredListOfServers(List<T> servers) {
        if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){
            List<T> filteredServers = Lists.newArrayList(Iterables.filter(
                    servers, this.zoneAffinityPredicate.getServerOnlyPredicate())); 
            if (shouldEnableZoneAffinity(filteredServers)) {
                return filteredServers;
            } else if (zoneAffinity) {
                overrideCounter.increment();
            }
        }
        return servers;
    }

	//是否启用区域感知功能,当符合以下一个条件就不启用该功能
	//1.故障实例百分比(断路器断开数/实例数量)>=0.8
	//2.实力平均负载>=0.6
	//3.可用实例数(实力数量-断路器断开数)<2
    private boolean shouldEnableZoneAffinity(List<T> filtered) {    
        if (!zoneAffinity && !zoneExclusive) {
            return false;
        }
        if (zoneExclusive) {
            return true;
        }
        LoadBalancerStats stats = getLoadBalancerStats();
        if (stats == null) {
            return zoneAffinity;
        } else {
            logger.debug("Determining if zone affinity should be enabled with given server list: {}", filtered);
            ZoneSnapshot snapshot = stats.getZoneSnapshot(filtered);
            double loadPerServer = snapshot.getLoadPerServer();
            int instanceCount = snapshot.getInstanceCount();            
            int circuitBreakerTrippedCount = snapshot.getCircuitTrippedCount();
            if (((double) circuitBreakerTrippedCount) / instanceCount >= blackOutServerPercentageThreshold.get() 
                    || loadPerServer >= activeReqeustsPerServerThreshold.get()
                    || (instanceCount - circuitBreakerTrippedCount) < availableServersThreshold.get()) {
                logger.debug("zoneAffinity is overriden. blackOutServerPercentage: {}, activeReqeustsPerServer: {}, availableServers: {}", 
                        new Object[] {(double) circuitBreakerTrippedCount / instanceCount,  loadPerServer, instanceCount - circuitBreakerTrippedCount});
                return false;
            } else {
                return true;
            }
            
        }
    }

  • DefaultNIWSServerListFilter:继承了ZoneAffinityServerListFilter区域感知过滤器,是默认的NIWS过滤器
  • ServerListSubsetFilter:继承ZoneAffinityServerListFilter,对已过滤的服务再次进行过滤
  • ZonePreferenceServerListFilter(同一zone):spring整合Eureka和Ribbon默认使用该过滤器,会根据配置或者eureka实例所属的区域来过滤出同区域的服务实例
    public List<Server> getFilteredListOfServers(List<Server> servers) {
        List<Server> output = super.getFilteredListOfServers(servers);
        if (this.zone != null && output.size() == servers.size()) {
            List<Server> local = new ArrayList();
            Iterator var4 = output.iterator();

            while(var4.hasNext()) {
                Server server = (Server)var4.next();
                if (this.zone.equalsIgnoreCase(server.getZone())) {
                    local.add(server);
                }
            }

            if (!local.isEmpty()) {
                return local;
            }
        }

        return output;
    }

ZoneAwareLoadBalancer
该负载均衡器创建了一个ConcurrentHashMap类型的balancers对象,存储了每个zone区域对应的负载均衡器,他会把所有服务实例视为一个zone下的节点看待,其主要方法是setServerListFroZones和chooseServer方法

    @Override
    protected void setServerListForZones(Map<String, List<Server>> zoneServersMap) {
        super.setServerListForZones(zoneServersMap);
        if (balancers == null) {
            balancers = new ConcurrentHashMap<String, BaseLoadBalancer>();
        }
        for (Map.Entry<String, List<Server>> entry: zoneServersMap.entrySet()) {
        	String zone = entry.getKey().toLowerCase();
            getLoadBalancer(zone).setServersList(entry.getValue());
        }
        // check if there is any zone that no longer has a server
        // and set the list to empty so that the zone related metrics does not
        // contain stale data
        for (Map.Entry<String, BaseLoadBalancer> existingLBEntry: balancers.entrySet()) {
            if (!zoneServersMap.keySet().contains(existingLBEntry.getKey())) {
                existingLBEntry.getValue().setServersList(Collections.emptyList()); //如果该区域下没有实例,将其清空
            }
        }
    }    
        
    @Override
    public Server chooseServer(Object key) {
        if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
            logger.debug("Zone aware logic disabled or there is only one zone");
            return super.chooseServer(key); //如果负载均衡器实例所属zone区域个数小于1,使用父类BaseLoadBalancer的chooseServer方法(过滤策略是RoundRobinRule)
        }
        Server server = null;
        try {
            LoadBalancerStats lbStats = getLoadBalancerStats();
            Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
            logger.debug("Zone snapshots: {}", zoneSnapshot);
            if (triggeringLoad == null) {
                triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
                        "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
            }

            if (triggeringBlackoutPercentage == null) {
                triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
                        "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
            }
            Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
            logger.debug("Available zones: {}", availableZones);
            if (availableZones != null &&  availableZones.size() < zoneSnapshot.keySet().size()) {
                String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);//使用ZoneAvoidanceRule过滤策略
                logger.debug("Zone chosen: {}", zone);
                if (zone != null) {
                    BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);
                    server = zoneLoadBalancer.chooseServer(key);
                }
            }
        } catch (Exception e) {
            logger.error("Error choosing server using zone aware logic for load balancer={}", name, e);
        }
        if (server != null) {
            return server;
        } else {
            logger.debug("Zone avoidance logic is not invoked.");
            return super.chooseServer(key);
        }
    }
3.负载均衡策略

springcloud Ribbon详解_第3张图片
IRule:

public interface IRule{

    public Server choose(Object key); //choose方法
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

AbstractLoadBalancerRule:

public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {

    private ILoadBalancer lb;
        
    //重写了loadBalancer设置和获取方法
    @Override
    public void setLoadBalancer(ILoadBalancer lb){
        this.lb = lb;
    }
    
    @Override
    public ILoadBalancer getLoadBalancer(){
        return lb;
    }      
}

RandomRule:

public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null; //负载均衡器为空
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) { //假如调用choose方法的线程为空,返回null
                return null;
            }
            List<Server> upList = lb.getReachableServers(); //负载均衡器方法
            List<Server> allList = lb.getAllServers(); //负载均衡器方法

            int serverCount = allList.size();
            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);

            if (server == null) { //该索引的server值为空 ,但一般不会发生,因为lb.getReachableServers()返回为空的话不会执行到这一步
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield(); //当前线程让步,但此时还具有竞争资源的能力,而且where循环没有退出
                continue;
            }

            if (server.isAlive()) { //该服务实例正常
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    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 clientConfig) {
		// TODO Auto-generated method stub
		
	}
}

RoundRobinRule:

public class RoundRobinRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;
    private static final boolean AVAILABLE_ONLY_SERVERS = true;
    private static final boolean ALL_SERVERS = false;

    private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

    public RoundRobinRule() {
        nextServerCyclicCounter = new AtomicInteger(0); //原子对象,用于多线程环境下CAS操作,用于线程遍历
    }

    public RoundRobinRule(ILoadBalancer lb) {
        this();
        setLoadBalancer(lb);
    }

	//重写了choose方法
    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;
            }

            int nextServerIndex = incrementAndGetModulo(serverCount); //多线程环境下增加索引值操作
            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;
    }

    /**
     * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
     *
     * @param modulo The modulo to bound the value of the counter.
     * @return The next value.
     */
    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next)) //原子操作,将current变为next
                return next;
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

RetryRule:

public class RetryRule extends AbstractLoadBalancerRule {
	IRule subRule = new RoundRobinRule(); //该方法默认使用roundrobinrule策略,但是增加了
	long maxRetryMillis = 500;

	...
	
	/*
	 * Loop if necessary. Note that the time CAN be exceeded depending on the
	 * subRule, because we're not spawning additional threads and returning
	 * early.
	 */
	 //重写了choose方法,在一定时间内进行重试(阈值为 maxRetryMillis +choose方法开始调用时间,也就是时间间隔为maxRetryMillis = 500)
	public Server choose(ILoadBalancer lb, Object key) {
		long requestTime = System.currentTimeMillis();
		long deadline = requestTime + maxRetryMillis;

		Server answer = null;

		answer = subRule.choose(key);

		if (((answer == null) || (!answer.isAlive()))
				&& (System.currentTimeMillis() < deadline)) {

			InterruptTask task = new InterruptTask(deadline
					- System.currentTimeMillis());

			while (!Thread.interrupted()) {
				answer = subRule.choose(key); //调用roundribonrule方法的choose方法线性遍历

				if (((answer == null) || (!answer.isAlive()))
						&& (System.currentTimeMillis() < deadline)) {
					/* pause and retry hoping it's transient */
					Thread.yield();
				} else {
					break;
				}
			}

			task.cancel();
		}

		if ((answer == null) || (!answer.isAlive())) {
			return null;
		} else {
			return answer;
		}
	}

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
	}
}

WeightedResponseTimeRule:

public class WeightedResponseTimeRule extends RoundRobinRule {
	private volatile List<Double> accumulatedWeights = new ArrayList<Double>();  //保存每个服务实例的权重值,每个索引对应值表示从索引0导当前索引的累加权重
	...
	//在设置负载均衡器时启动了一个定时任务,为每个服务实例计算权重,默认每30秒执行一次(30 * 1000)
	@Override
    public void setLoadBalancer(ILoadBalancer lb) {
        super.setLoadBalancer(lb);
        if (lb instanceof BaseLoadBalancer) {
            name = ((BaseLoadBalancer) lb).getName();
        }
        initialize(lb);
    }

    void initialize(ILoadBalancer lb) {        
        if (serverWeightTimer != null) {
            serverWeightTimer.cancel();
        }
        serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-"
                + name, true);
        serverWeightTimer.schedule(new DynamicServerWeightTask(), 0,
                serverWeightTaskTimerInterval);
        // do a initial run
        ServerWeight sw = new ServerWeight();
        sw.maintainWeights();

        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                logger
                        .info("Stopping NFLoadBalancer-serverWeightTimer-"
                                + name);
                serverWeightTimer.cancel();
            }
        }));
    }

	class DynamicServerWeightTask extends TimerTask {
        public void run() {
            ServerWeight serverWeight = new ServerWeight();
            try {
                serverWeight.maintainWeights();
            } catch (Exception e) {
                logger.error("Error running DynamicServerWeightTask for {}", name, e);
            }
        }
    }

    class ServerWeight {

        public void maintainWeights() {
            ILoadBalancer lb = getLoadBalancer();
            if (lb == null) {
                return;
            }
            
            if (!serverWeightAssignmentInProgress.compareAndSet(false,  true))  {
                return; 
            }
            
            try {
            	//计算权重 计算规则为:weightSoFar + totalResponseTime - 实例的平均响应时间!!
                logger.info("Weight adjusting job started");
                AbstractLoadBalancer nlb = (AbstractLoadBalancer) lb;
                LoadBalancerStats stats = nlb.getLoadBalancerStats();
                if (stats == null) {
                    // no statistics, nothing to do
                    return;
                }
                double totalResponseTime = 0;
                // find maximal 95% response time
                for (Server server : nlb.getAllServers()) {
                    // this will automatically load the stats if not in cache
                    ServerStats ss = stats.getSingleServerStat(server);
                    totalResponseTime += ss.getResponseTimeAvg();
                }
                // weight for each server is (sum of responseTime of all servers - responseTime)
                // so that the longer the response time, the less the weight and the less likely to be chosen
                Double weightSoFar = 0.0;
                
                // create new list and hot swap the reference
                List<Double> finalWeights = new ArrayList<Double>();
                for (Server server : nlb.getAllServers()) {
                    ServerStats ss = stats.getSingleServerStat(server);
                    double weight = totalResponseTime - ss.getResponseTimeAvg();
                    weightSoFar += weight;
                    finalWeights.add(weightSoFar);   
                }
                setWeights(finalWeights);
            } catch (Exception e) {
                logger.error("Error calculating server weights", e);
            } finally {
                serverWeightAssignmentInProgress.set(false);
            }

        }
    }
    ...
  	//choose方法
  	@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    @Override
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            // get hold of the current reference in case it is changed from the other thread
            List<Double> currentWeights = accumulatedWeights; //获取服务实例的权重值
            if (Thread.interrupted()) { //线程已被表示阻塞
                return null;
            }
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();

            if (serverCount == 0) {
                return null;
            }

            int serverIndex = 0;

            // last one in the list is the sum of all weights
            double maxTotalWeight = currentWeights.size() == 0 ? 0 : currentWeights.get(currentWeights.size() - 1); 
            // No server has been hit yet and total weight is not initialized
            // fallback to use round robin
            if (maxTotalWeight < 0.001d || serverCount != currentWeights.size()) { //如果最后一个服务实例的权重值小于0.01,则采用roundrobinrule的策略
                server =  super.choose(getLoadBalancer(), key);
                if(server == null) {
                    return server;
                }
            } else {
                // generate a random weight between 0 (inclusive) to maxTotalWeight (exclusive)
                double randomWeight = random.nextDouble() * maxTotalWeight; //产生随机数,哪个服务实例的权重区间有这个值,即挑选该服务作为执行请求的服务实例
                // pick the server index based on the randomIndex
                int n = 0;
                for (Double d : currentWeights) {
                    if (d >= randomWeight) {
                        serverIndex = n;
                        break;
                    } else {
                        n++;
                    }
                }

                server = allList.get(serverIndex);
            }

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

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

            // Next.
            server = null;
        }
        return server;
    }  
    ...

ClientConfigEnabledRoundRobinRule(一般作为父类,其策略为roundribonrule):

public class ClientConfigEnabledRoundRobinRule extends AbstractLoadBalancerRule {

    RoundRobinRule roundRobinRule = new RoundRobinRule();

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        roundRobinRule = new RoundRobinRule();
    }

    @Override
    public void setLoadBalancer(ILoadBalancer lb) {
    	super.setLoadBalancer(lb);
    	roundRobinRule.setLoadBalancer(lb);
    }
    
    @Override
    public Server choose(Object key) {
        if (roundRobinRule != null) {
            return roundRobinRule.choose(key);
        } else {
            throw new IllegalArgumentException(
                    "This class has not been initialized with the RoundRobinRule class");
        }
    }

}

BestAvailableRule(minimalConcurrentConnections最小):

    @Override
    public Server choose(Object key) {
        if (loadBalancerStats == null) {
            return super.choose(key);
        }
        List<Server> serverList = getLoadBalancer().getAllServers();
        int minimalConcurrentConnections = Integer.MAX_VALUE;
        long currentTime = System.currentTimeMillis();
        Server chosen = null;
        for (Server server: serverList) {
            ServerStats serverStats = loadBalancerStats.getSingleServerStat(server); //从loadBalancerStats(负载均衡器属性对象)中获取相关信息进行选择
            if (!serverStats.isCircuitBreakerTripped(currentTime)) {
                int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
                if (concurrentConnections < minimalConcurrentConnections) {
                    minimalConcurrentConnections = concurrentConnections; //比较交换获取并发请求数最小的服务实例(选出最空闲的实例)
                    chosen = server;
                }
            }
        }
        if (chosen == null) { //假如loadBalancerStats没有数据,使用父类策略
            return super.choose(key);
        } else {
            return chosen;
        }
    }

PredicateBasedRule:

public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
   
    /**
     * Method that provides an instance of {@link AbstractServerPredicate} to be used by this class.
     * 
     */
    public abstract AbstractServerPredicate getPredicate(); //过滤接口,子类对其chooseRoundRobinAfterFiltering进行实现
        
    @Override
    public Server choose(Object key) {
        ILoadBalancer lb = getLoadBalancer();
        Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key); //以线性轮询的方式过滤服务实例
        if (server.isPresent()) {
            return server.get();
        } else {
            return null;
        }       
    }
}

//chooseRoundRobinAfterFiltering存在AbstractServerPredicate抽象方法中
public abstract class AbstractServerPredicate implements Predicate<PredicateKey> {
		...
	    public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
        List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
        if (eligible.size() == 0) {
            return Optional.absent();
        }
        return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
    	}
        public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
        if (loadBalancerKey == null) {
            return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));            
        } else {
            List<Server> results = Lists.newArrayList();
            for (Server server: servers) {
                if (this.apply(new PredicateKey(loadBalancerKey, server))) { //最终调的是apply方法,子类对apply实现
                    results.add(server);
                }
            }
            return results;            
        }
    }
    ...
}

AvailabilityFilteringRule(线性抽样空闲server):

public class AvailabilityFilteringRule extends PredicateBasedRule {    

    private AbstractServerPredicate predicate; //apply在AbstractServerPredicate 实现类中实现
    
    @Override
    public Server choose(Object key) {
        int count = 0;
        Server server = roundRobinRule.choose(key); //先使用roundrobinrule进行过滤
        while (count++ <= 10) {
            if (predicate.apply(new PredicateKey(server))) { //再使用apply对其过滤,10次没找到,使用父类roundrobinrule的choose方法
                return server;
            }
            server = roundRobinRule.choose(key);
        }
        return super.choose(key);
    }
    ...
}

ZoneAvoidanceRule(对每个zone区域的服务实例进行过滤):

public class ZoneAvoidanceRule extends PredicateBasedRule {

    private CompositePredicate compositePredicate; //其过滤方法使用的是CompositePredicate
    
    public ZoneAvoidanceRule() {
        super();
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
    }
	...
}
	public class CompositePredicate extends AbstractServerPredicate {
	...
	//获取有资格的服务
	@Override
    public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) { 
        List<Server> result = super.getEligibleServers(servers, loadBalancerKey);
        Iterator<AbstractServerPredicate> i = fallbacks.iterator();
        while (!(result.size() >= minimalFilteredServers && result.size() > (int) (servers.size() * minimalFilteredPercentage)) //过滤后的实例总数>1 && 过滤后的实例比例 > 0才会执行下列过滤策略
                && i.hasNext()) {
            AbstractServerPredicate predicate = i.next();
            result = predicate.getEligibleServers(servers, loadBalancerKey);
        }
        return result;
    }
	...
}

重试机制

Eureka强调CAP中的AP(可用性,可靠性),而牺牲C(一致性),因此服务调用时需要加入重试机制,增强容错性。
yml文件中添加如下内容:

spring.cloud.loadbalancer.retry.enabled = true # 开启重试机制
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds = 10000 # 断路器的超时时间需大于ribbon的超时时间
{服务名}.ribbon.ConnectTimeout = 250 #请求连接的超时时间
{服务名}.ribbon.ReadTimeout = 1000 #请求处理的超时时间
{服务名}.ribbon.OkToRetryOnAllOperations=true #对所有请求操作都进行重试
{服务名}.ribbon.MaxAutoRetriesNextServer = 2 #切换实例的重试次数
{服务名}.ribbon.MaxAutoRetries = 1 #对当前实例的重试次数

参考资料:《springcloud 微服务实战》

你可能感兴趣的:(微服务,java,ribbon,ribbon)