本文主要研究一下eureka的ZoneAffinityServerListFilterjava
ribbon-loadbalancer-2.2.5-sources.jar!/com/netflix/loadbalancer/ZoneAffinityServerListFilter.javaspring
/** * This server list filter deals with filtering out servers based on the Zone affinity. * This filtering will be turned on if either {@link CommonClientConfigKey#EnableZoneAffinity} * or {@link CommonClientConfigKey#EnableZoneExclusivity} is set to true in {@link IClientConfig} object * passed into this class during initialization. When turned on, servers outside the same zone (as * indicated by {@link Server#getZone()}) will be filtered out. By default, zone affinity * and exclusivity are turned off and nothing is filtered out. * * @author stonse * */ public class ZoneAffinityServerListFilter<T extends Server> extends AbstractServerListFilter<T> implements IClientConfigAware { //...... @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; } }
能夠看到這裏首先調用了zoneAffinityPredicate.getServerOnlyPredicate()進行過濾;而後再調用shouldEnableZoneAffinity判斷是否真的須要返回過濾後的數據。
ribbon-loadbalancer-2.2.5-sources.jar!/com/netflix/loadbalancer/ZoneAffinityPredicate.javaapp
/** * A predicate the filters out servers that are not in the same zone as the client's current * zone. The current zone is determined from the call * * <pre>{@code * ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone); * }</pre> * * @author awang * */ public class ZoneAffinityPredicate extends AbstractServerPredicate { private final String zone = ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone); public ZoneAffinityPredicate() { } @Override public boolean apply(PredicateKey input) { Server s = input.getServer(); String az = s.getZone(); if (az != null && zone != null && az.toLowerCase().equals(zone.toLowerCase())) { return true; } else { return false; } } }
能夠看到這裏對server的zone進行判斷,相同的zone才選取出來。
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; } } }
這裏進行判斷,若是目標zone的server統計數據不是太好,達到斷路的標準,則不會返回該zone的server。
spring-cloud-netflix-ribbon-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilter.javaide
/** * A filter that actively prefers the local zone (as defined by the deployment context, or * the Eureka instance metadata). * * @author Dave Syer */ public class ZonePreferenceServerListFilter extends ZoneAffinityServerListFilter<Server> { //...... @Override 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<>(); for (Server server : output) { if (this.zone.equalsIgnoreCase(server.getZone())) { local.add(server); } } if (!local.isEmpty()) { return local; } } return output; } }
Spring Cloud的ZonePreferenceServerListFilter繼承了eureka的ZoneAffinityServerListFilter,重寫了getFilteredListOfServers方法,即eureka的ZoneAffinityServerListFilter計算出來沒有根據zone過濾的話,那麼它會再過濾一次,選出跟實例相同zone的server。注意這裏進行了判斷,如根據zone過濾出來爲空,則返回父類過濾出來server,即再也不根據zone進行過濾。
eureka提供了ZoneAffinityServerListFilter,能夠對server進行zone親和性過濾,同時還會根據server的健康統計判斷是否須要使用進行zone親和過濾後的server,若是不該該開啓,則返回沒有過濾的server列表。好比沒有跟該實例相同zone的server列表,那麼很明顯就是不該該返回根據zone進行過濾後的空列表。ui