springCloud Ribbon源码浅析

springboot 版本2.1.3.RELEASE
springCloud版本Greenwich.RELEASE

LoadBalancerAutoConfiguration

截取重要部分

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

    //这里的LoadBalanced整合了@Qualifier
    //加载所有带@LoadBalanced标示的RestTemplate集合
	@LoadBalanced
	@Autowired(required = false)
	private List<RestTemplate> restTemplates = Collections.emptyList();

    
	@Bean
	public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
			final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
		return () -> restTemplateCustomizers.ifAvailable(customizers -> {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
                for (RestTemplateCustomizer customizer : customizers) {
                    customizer.customize(restTemplate);
                }
            }
        });
	}

    @Autowired(required = false)
	private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

	@Bean
	@ConditionalOnMissingBean
	public LoadBalancerRequestFactory loadBalancerRequestFactory(
			LoadBalancerClient loadBalancerClient) {
		return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
	}

	@Configuration
	@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
	static class LoadBalancerInterceptorConfig {
		//创建LoadBalancerInterceptor拦截器
        @Bean
		public LoadBalancerInterceptor ribbonInterceptor(
				LoadBalancerClient loadBalancerClient,
				LoadBalancerRequestFactory requestFactory) {
			return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
		}

        //将拦截器加入到restTemplate中
		@Bean
		@ConditionalOnMissingBean
		public RestTemplateCustomizer restTemplateCustomizer(
				final LoadBalancerInterceptor loadBalancerInterceptor) {
			return restTemplate -> {
                List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                        restTemplate.getInterceptors());
                list.add(loadBalancerInterceptor);
                restTemplate.setInterceptors(list);
            };
		}
	}
}

接上面LoadBalancerInterceptor拦截器中

    public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

    //这里的LoadBalancerClient默认是引用RibbonLoadBalancerClient
	private LoadBalancerClient loadBalancer;
	private LoadBalancerRequestFactory requestFactory;

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

	public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
		// for backwards compatibility
		this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
	}
    
	@Override
	public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
			final ClientHttpRequestExecution execution) throws IOException {
		final URI originalUri = request.getURI();
		String serviceName = originalUri.getHost();
		Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        //重点在这里RibbonLoadBalancerClient.execute
		return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
	}
}


//在这里引入了RibbonLoadBalancerClient
@Configuration
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
@RibbonClients
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
    @Bean
	@ConditionalOnMissingBean(LoadBalancerClient.class)
	public LoadBalancerClient loadBalancerClient() {
		return new RibbonLoadBalancerClient(springClientFactory());
	}
}

继续看RibbonLoadBalancerClient.execute

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
		//springCloud使用了ZoneAwareLoadBalancer实现类
        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);
	}
    
    
    @Override
	public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
		Server server = null;
		if(serviceInstance instanceof RibbonServer) {
			server = ((RibbonServer)serviceInstance).getServer();
		}
		if (server == null) {
			throw new IllegalStateException("No instances available for " + serviceId);
		}

		RibbonLoadBalancerContext context = this.clientFactory
				.getLoadBalancerContext(serviceId);
		RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

		try {
           //传入需要请求的服务实例定义serviceInstance,里面包括了实例id、端口、地址等信息
           //到这一步Ribbon拦截结束,调用ClientHttpRequestExecution.execute
			T returnVal = request.apply(serviceInstance);
            //Ribbon对服务请求进行了跟踪将调用的情况存入ServerStats中
			//后续负载均衡器进行choose计算时会使用到
			statsRecorder.recordStats(returnVal);
			return returnVal;
		}
		// catch IOException and rethrow so RestTemplate behaves correctly
		catch (IOException ex) {
			statsRecorder.recordStats(ex);
			throw ex;
		}
		catch (Exception ex) {
			statsRecorder.recordStats(ex);
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		return null;
	}

在这里重点是ILoadBalancer接口

public interface ILoadBalancer {
    //添加新的服务实例
    void addServers(List<Server> var1);
    
    //根据一个key选择服务实例
    Server chooseServer(Object var1);

    //标记一个服务实例down
    void markServerDown(Server var1);

    /** @deprecated */
    @Deprecated
    List<Server> getServerList(boolean var1);

    //获取所有可用的服务实例(UP)
    List<Server> getReachableServers();

    //获取所有的服务实例
    List<Server> getAllServers();
}

看一下有哪些实现类
fcc717f487cc0980636365001e6ba28a.png

这里springCloud使用了ZoneAwareLoadBalancer

@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {
    @Bean
	@ConditionalOnMissingBean
	public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
			ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
			IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
		if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
			return this.propertiesFactory.get(ILoadBalancer.class, config, name);
		}
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}
}

接下来看下ILoadBalancer的各个具体实现

AbstractLoadBalancer
public abstract class AbstractLoadBalancer implements ILoadBalancer {
    
    //定义了服务的分组
    public enum ServerGroup{
        ALL,
        STATUS_UP,
        STATUS_NOT_UP        
    }
    
    public Server chooseServer() {
    	return chooseServer(null);
    }

   
    public abstract List<Server> getServerList(ServerGroup serverGroup);
    
    //LoadBalancerStats被用来存储各个服务实例的当前属性和统计信息,是制定负载均衡策略的重要依据
    public abstract LoadBalancerStats getLoadBalancerStats();    
}
BaseLoadBalancer

截取部分重要代码

//Ribbon负载均衡器的基本实现
public class BaseLoadBalancer extends AbstractLoadBalancer implements
        PrimeConnections.PrimeConnectionListener, IClientConfigAware {
    
    //默认的负载规则,轮询
    private final static IRule DEFAULT_RULE = new RoundRobinRule();
    //默认的ping策略,线性检查服务状态
    private final static SerialPingStrategy DEFAULT_PING_STRATEGY = new SerialPingStrategy();
    
    //检查服务是否存活,实现boolean isAlive(Server server)方法
    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>());
            
   public BaseLoadBalancer() {
        this.name = DEFAULT_NAME;
        this.ping = null;
        setRule(DEFAULT_RULE);
        //启动一个健康检查任务 10秒检查一次
        setupPingTask();
        lbStats = new LoadBalancerStats(DEFAULT_NAME);
    }
    
    //选择一个具体服务实例,最终是交给IRule接口处理
    public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
}
DynamicServerListLoadBalancer

ServerList


public class DynamicServerListLoadBalancer<T extends Server> extends BaseLoadBalancer {
    
    //ServerList接口封装了对serverList的处理,定义了俩个方法 分别处理serverList的初始化和更新
    volatile ServerList<T> serverListImpl;
    
    protected final ServerListUpdater.UpdateAction updateAction = new ServerListUpdater.UpdateAction() {
        @Override
        public void doUpdate() {
            //这个方法最终调用了serverListImpl.getUpdatedListOfServers()更新serverList列表
            updateListOfServers();
        }
    };
    
    
    @VisibleForTesting
    public void updateListOfServers() {
        List<T> servers = new ArrayList<T>();
        if (serverListImpl != null) {
            //调用ServerList接口更新serverList列表
            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);
    }
    
    //服务更新器,默认实现类是PollingServerListUpdater
    //实现了synchronized void start(final UpdateAction updateAction),开启定时器30秒调用一次doUpdate()
    protected volatile ServerListUpdater serverListUpdater;
    //
    public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,
                                         ServerList<T> serverList, ServerListFilter<T> filter,
                                         ServerListUpdater serverListUpdater) {
        super(clientConfig, rule, ping);
        this.serverListImpl = serverList;
        this.filter = filter;
        this.serverListUpdater = serverListUpdater;
        if (filter instanceof AbstractServerListFilter) {
            ((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());
        }
        //这里最终会调用serverListUpdater.start(final UpdateAction updateAction)
        restOfInit(clientConfig);
    }
}

ServerList接口封装了对serverList的处理,springCloud的实现类DomainExtractingServerList,最终调用了com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList,从eureka获取serverList

public interface ServerList<T extends Server> {

    public List<T> getInitialListOfServers();
    
  
    public List<T> getUpdatedListOfServers();   

}

//在这里springCloud创建了DomainExtractingServerList实现ServerList接口,最终委派给DiscoveryEnabledNIWSServerList处理
@Configuration
public class EurekaRibbonClientConfiguration {
    @Bean
	@ConditionalOnMissingBean
	public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
		if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
			return this.propertiesFactory.get(ServerList.class, config, serviceId);
		}
		DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
				config, eurekaClientProvider);
		DomainExtractingServerList serverList = new DomainExtractingServerList(
				discoveryServerList, config, this.approximateZoneFromHostname);
		return serverList;
	}
}

服务更新器ServerListUpdater
4803617076f36f0d469cb1fa6b061b6a.png

public interface ServerListUpdater {

    /**
     * 实现更新的具体操作
     */
    public interface UpdateAction {
        void doUpdate();
    }

    /**
     * 开启服务更新器,调用updateAction
     */
    void start(UpdateAction updateAction);

    /**
     * 停止服务更新器
     */
    void stop();

    /**
     * 获取最近的更新时间戳
     */
    String getLastUpdate();

    /**
     * 获取上一次更新到现在的间隔 毫秒
     */
    long getDurationSinceLastUpdateMs();

    /**
     * 获取错过的更新周期数
     */
    int getNumberMissedCycles();

    /**
     * 获取核心线程数
     */
    int getCoreThreads();
}

ServerListFilter过滤器,在updateListOfServers方法中调用

 volatile ServerListFilter<T> filter;

@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);
    }

ServerListFilter接口定义

public interface ServerListFilter<T extends Server> {

    public List<T> getFilteredListOfServers(List<T> servers);

}

看一下有哪些可用的过滤器
在这里插入图片描述
其中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
基于区域感知的方式实现服务实例过滤

public List<T> getFilteredListOfServers(List<T> servers) {
        //根据自身的zone和服务实例配置的zone进行匹配
        if (zone != null && (zoneAffinity || zoneExclusive) && servers !=null && servers.size() > 0){
            List<T> filteredServers = Lists.newArrayList(Iterables.filter(
                    servers, this.zoneAffinityPredicate.getServerOnlyPredicate()));
            //这里对筛选后的结果进行一次分析,用到了LoadBalancerStats和serverStats
            //分析内容 故障实例百分比、实例平均负载、可用实例数
            //如果发现上面的内容有一项不符合要求则放弃此次过滤,保证跨区域高可用
            if (shouldEnableZoneAffinity(filteredServers)) {
                return filteredServers;
            } else if (zoneAffinity) {
                overrideCounter.increment();
            }
        }
        return servers;
    }

DefaultNIWSServerListFilter完全继承ZoneAffinityServerListFilter
netfix默认使用该过滤器

ServerListSubsetFilter,继承于ZoneAffinityServerListFilter,通常用在大规模服务器集群
他除了区域感知之外,还能对剩下的服务实例进行筛选,剔除相对不够健康的实例

ZonePreferenceServerListFilter继承于ZoneAffinityServerListFilter,springCloud默认使用的过滤器
对原server进行包装,将eureka实例元数据中的zone设置到server中

@Override
	public List<Server> getFilteredListOfServers(List<Server> servers) {
        //先使用父类ZoneAffinityServerListFilter进行过滤
		List<Server> output = super.getFilteredListOfServers(servers);
        //将结果再按照zone进行过滤,只保留zone相同的实例
		if (this.zone != null && output.size() == servers.size()) {
			List<Server> local = new ArrayList<>();
			for (Server server : output) {
				if (this.zone.equalsIgnoreCase(server.getZone())) {
					local.add(server);
				}
			}
			if (!local.isEmpty()) {
				return local;
			}
		}
		return output;
	}
    
    //扩展netflix原有的server
    class DomainExtractingServer extends DiscoveryEnabledServer {
        public DomainExtractingServer(DiscoveryEnabledServer server, boolean useSecurePort,
			boolean useIpAddr, boolean approximateZoneFromHostname) {
		// host and port are set in super()
		super(server.getInstanceInfo(), useSecurePort, useIpAddr);
		//从eureka服务实例的元对象中获取zone值放入server中
        if (server.getInstanceInfo().getMetadata().containsKey("zone")) {
			setZone(server.getInstanceInfo().getMetadata().get("zone"));
		}
		else if (approximateZoneFromHostname) {
			setZone(ZoneUtils.extractApproximateZone(server.getHost()));
		}
		else {
			setZone(server.getZone());
		}
		setId(extractId(server));
		setAlive(server.isAlive());
		setReadyToServe(server.isReadyToServe());
    }

配置写法

##设定自己是北京的服务器
eureka.instance.metadata-map.zone=beijing
ZoneAwareLoadBalancer

ZoneAwareLoadBalancer继承于DynamicServerListLoadBalancer
BaseLoadBalancer中的chooseServer使用的规则是RoundRobinRule轮询,这样可能会产生周期性的跨区域访问,ZoneAwareLoadBalancer就是解决这个问题,加入了区域感知的规则

@Override
    //DynamicServerListLoadBalancer.java
    //更新serverList后将所有的server按照key=zone value=List<Server>组装成map
    protected void setServerListForZones(
            Map<String, List<Server>> zoneServersMap) {
        LOGGER.debug("Setting server list for zones: {}", zoneServersMap);
        //将这个组装好的map跟新到LoadBalancerStats中
        getLoadBalancerStats().updateZoneServerMapping(zoneServersMap);
    }


        private ConcurrentHashMap<String, BaseLoadBalancer> balancers = new ConcurrentHashMap<String, BaseLoadBalancer>();


    //ZoneAwareLoadBalancer.java
    //重写了这个方法,在调用父类方法之后自己组装了一个balancers,每个zone单独创建一个BaseLoadBalancer,并且将该zone的serverList集合放入到相对应的BaseLoadBalancer中
    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());
        }
        
        //这里做一个校验,去除那些失效的zone
        for (Map.Entry<String, BaseLoadBalancer> existingLBEntry: balancers.entrySet()) {
            if (!zoneServersMap.keySet().contains(existingLBEntry.getKey())) {
                existingLBEntry.getValue().setServersList(Collections.emptyList());
            }
        }
    }
    
    //这里重写了 BaseLoadBalancer的chooseServer方法
    @Override
    public Server chooseServer(Object key) {
        //如果可用的zone不大于1,则直接调用默认的chooseServer
        if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
            logger.debug("Zone aware logic disabled or there is only one zone");
            return super.chooseServer(key);
        }
        Server server = null;
        try {
            //这一段的逻辑是通过ZoneAvoidanceRule来进行zone可用性的判断
            //判断的依据是根据负载的阙值默认为小于0.2、断路器开关次数/实例总数小于0.99999
            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);
            //成功筛选出一个zone,通过balancers获取相应的BaseLoadBalancer进行chooseServer
            if (availableZones != null &&  availableZones.size() < zoneSnapshot.keySet().size()) {
                String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);
                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.");
            //否则调用父类默认的chooseServer
            return super.chooseServer(key);
        }
    }
    
IRule

在这里插入图片描述
AbstractLoadBalancerRule
抽象类,定义了获取ILoadBalancer

RandomRule
随机获取一个服务实例

RoundRobinRule
轮询

RetryRule
本质上还是RandomRule,内部维护了一个RoundRobinRule,默认在500M内进行循环尝试,最终获得Server或者返回null

WeightedResponseTimeRule
根据服务实例的响应时间计算权重区间,区间越大选取的概率就越大

区间宽度 = 所有实例的总响应时间 - 该实例的平均响应时间

ClientConfigEnabledRoundRobinRule
一个基类,内部定义了RoundRobinRule,方便子类在备选方案上可以调用

BestAvailableRule
继承ClientConfigEnabledRoundRobinRule,注入LoadBalancerStats
通过LoadBalancerStats过滤故障的实例,然后选择最小并发量的实例

PredicateBasedRule
抽象类,基于google的Predicate类实现了一个过滤器,方便子类制定过滤规则,过滤后的服务实例再通过轮询获取

AvailabilityFilteringRule
继承PredicateBasedRule,实现了一个过滤规则
过滤断路器已生效的实例,过滤并发请求数大于阙值的实例 默认是Integer.MAX

ZoneAvoidanceRule
继承PredicateBasedRule 先进行可用zone的过滤再执行availabilityPredicate的过滤

ribbon配置项
<clientName>.ribbon.NFLoadBalancerClassName: Should implement ILoadBalancer
<clientName>.ribbon.NFLoadBalancerRuleClassName: Should implement IRule
<clientName>.ribbon.NFLoadBalancerPingClassName: Should implement IPing
<clientName>.ribbon.NIWSServerListClassName: Should implement ServerList
<clientName>.ribbon.NIWSServerListFilterClassName: Should implement ServerListFilter

实例

users:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule

在使用了eureka的前提下 springCloud 已经帮我们默认配置好了合适的接口实现类

@Configuration
public class EurekaRibbonClientConfiguration {
    
    //com.netflix.niws.loadbalancer.NIWSDiscoveryPing
    @Bean
	@ConditionalOnMissingBean
	public IPing ribbonPing(IClientConfig config) {
		if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
			return this.propertiesFactory.get(IPing.class, config, serviceId);
		}
		NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
		ping.initWithNiwsConfig(config);
		return ping;
	}
    
    //org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList
    @Bean
	@ConditionalOnMissingBean
	public ServerList<?> ribbonServerList(IClientConfig config, Provider<EurekaClient> eurekaClientProvider) {
		if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
			return this.propertiesFactory.get(ServerList.class, config, serviceId);
		}
		DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
				config, eurekaClientProvider);
		DomainExtractingServerList serverList = new DomainExtractingServerList(
				discoveryServerList, config, this.approximateZoneFromHostname);
		return serverList;
	}
}

@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties
//Order is important here, last should be the default, first should be optional
// see https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653
@Import({HttpClientConfiguration.class, OkHttpRibbonConfiguration.class, RestClientRibbonConfiguration.class, HttpClientRibbonConfiguration.class})
public class RibbonClientConfiguration {

    //com.netflix.loadbalancer.ZoneAvoidanceRule
    @Bean
	@ConditionalOnMissingBean
	public IRule ribbonRule(IClientConfig config) {
		if (this.propertiesFactory.isSet(IRule.class, name)) {
			return this.propertiesFactory.get(IRule.class, config, name);
		}
		ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
		rule.initWithNiwsConfig(config);
		return rule;
	}
    
    //com.netflix.loadbalancer.ZoneAwareLoadBalancer
    @Bean
	@ConditionalOnMissingBean
	public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
			ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
			IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
		if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
			return this.propertiesFactory.get(ILoadBalancer.class, config, name);
		}
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}

    //org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter
	@Bean
	@ConditionalOnMissingBean
	@SuppressWarnings("unchecked")
	public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
		if (this.propertiesFactory.isSet(ServerListFilter.class, name)) {
			return this.propertiesFactory.get(ServerListFilter.class, config, name);
		}
		ZonePreferenceServerListFilter filter = new ZonePreferenceServerListFilter();
		filter.initWithNiwsConfig(config);
		return filter;
	}
}
  

如果需要替换这些默认的实现类 只要在application.properties定义即可 或者直接定义自己的bean

springCloud 重试机制配置

ribbon 所有的配置在 CommonClientConfigKey类

##开启重试机制,默认是开启的
spring.cloud.loadbalancer.retry.enabled=true

# 对同样的server最多进行一次重试,除掉最开始的访问
sample-client.ribbon.MaxAutoRetries=1

# 最多切换一次服务重试
sample-client.ribbon.MaxAutoRetriesNextServer=1

# 默认情况只对get资源进行重试,如果配置了该项,则对post等请求也会重试
sample-client.ribbon.OkToRetryOnAllOperations=true


# 请求连接超时,默认2秒
sample-client.ribbon.ConnectTimeout=3000

# 请求处理超时,默认5秒
sample-client.ribbon.ReadTimeout=3000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值