@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); } 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); logger.debug("Zone chosen: {}", zone); if (zone != null) { BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone); server = zoneLoadBalancer.chooseServer(key); } } } catch (Throwable e) { logger.error("Unexpected exception when choosing server using zone aware logic", e); } if (server != null) { return server; } else { logger.debug("Zone avoidance logic is not invoked."); return super.chooseServer(key); } }
/** * @param availableServerStats the server instances to choose from * @return the nearest, less loaded server instance * @see {@link LoadBalancer#choose(java.util.List)} */ @Override public ServerStats choose(List<ServerStats> availableServerStats) { // cache properties to speed up loop double maxRequestsPerSecond = propMaxRequestsPerSecond.get(); double escapeAreaThreshold = propEscapeAreaThreshold.get(); double escapeRegionThreshold = propEscapeRegionThreshold.get(); double escapeAvailabilityThreshold = propEscapeAvailabilityThreshold.get(); // find the best available server MetaData max = null; for (ServerStats stat : availableServerStats) { ServerStats s = (ServerStats) stat; ServerInstance instance = s.getServerInstance(); MetaData meta = new MetaData(); meta.location = locations.getUnchecked(s); meta.server = s; meta.load = s.getSentMessagesPerSecond() / maxRequestsPerSecond; meta.sessionCount = s.getOpenSessionsCount(); meta.locationBits = 0; if (myLocation.getAvailabilityZone().equals(meta.location.getAvailabilityZone())) { // same availability zone meta.locationBits = 7; } else if (myLocation.getRegion().equals(meta.location.getRegion())) { // same region meta.locationBits = 3; } else if (myLocation.getArea().equals(meta.location.getArea())) { // same area meta.locationBits = 1; } // keep the best server instance if (max == null) { max = meta; } else if (meta.isBetterThan( max, escapeAreaThreshold, escapeRegionThreshold, escapeAvailabilityThreshold)) { max = meta; } } if (max != null) { if (metricRegistry != null) { Counter counter = availabilityZoneToCounter.get(max.location.getAvailabilityZone()); if (counter == null) { counter = metricRegistry.counter( name(serviceName, "az-requests", max.location.getAvailabilityZone())); Counter prevCount = availabilityZoneToCounter.putIfAbsent(max.location.getAvailabilityZone(), counter); if (prevCount != null) { // another thread snuck in their counter during a race condition so use it instead. counter = prevCount; } } counter.inc(); } return max.server; } else { return null; } }