序
本文主要研究一下eureka的ZoneAffinityServerListFilter
ZoneAffinityServerListFilter
ribbon-loadbalancer-2.2.5-sources.jar!/com/netflix/loadbalancer/ZoneAffinityServerListFilter.java
/**
* 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判断是否真的需要返回过滤后的数据。
ZoneAffinityPredicate
ribbon-loadbalancer-2.2.5-sources.jar!/com/netflix/loadbalancer/ZoneAffinityPredicate.java
/**
* 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才选取出来。
shouldEnableZoneAffinity
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。
ZonePreferenceServerListFilter
spring-cloud-netflix-ribbon-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/ribbon/ZonePreferenceServerListFilter.java
/**
* 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进行过滤后的空列表。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。