sequence

In this paper, we study the 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(); }}returnservers; }}Copy the code

Here you can see the first call zoneAffinityPredicate. GetServerOnlyPredicate () filtering; Then call shouldEnableZoneAffinity to see if you really need to return the filtered data.

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 * * 
{@code * ConfigurationManager.getDeploymentContext().getValue(ContextKey.zone); * }

* * @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; }}}Copy the code

You can see that the zone of the server is judged and the same zone is selected.

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; }}}Copy the code

If the server statistics of the target zone are not good enough to meet the criteria of disconnection, the server of this zone will not be returned.

ZonePreferenceServerListFilter

Spring – the cloud – netflix – ribbon – 2.0.0. RC1 – sources. The 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; }}returnoutput; }}Copy the code

Spring Cloud ZonePreferenceServerListFilter inherited eureka ZoneAffinityServerListFilter, rewrite the getFilteredListOfServers method, Namely eureka ZoneAffinityServerListFilter calculated without filtering according to the zone, so it will filter it again, to select the server with the same instance zones. Note that the server is not filtered by zone. If the server is not filtered by zone, the server is filtered by zone.

summary

Provided ZoneAffinityServerListFilter eureka, the server can be zone affinity filtration, at the same time according to the health of the server will determine whether you need to use the server after zone affinity filtration, if should not be open, The list of unfiltered servers is returned. For example, if there is no list of servers in the same zone as this instance, it is obvious that an empty list filtered by zone should not be returned.

doc

  • HA and Zone Affinity with Spring Cloud Netflix Eureka