通過LoadBalancer從一個服務對應的server list中選擇一個server出來,保持負載均衡,將請求均勻的打到各個服務器上去
LoadBalancer的chooseServer()方法,通過自己內置的負載均衡算法,選擇一個server出來
ZoneAwareLoadBalancer,Zone根本不用管他,因爲我們這裏暫時沒有Zone的概念,機房的概念,多機房的話,他這裏可以感知到多機房的,將一個機房裏的請求,轉發給自己這個機房裏部署的其他的服務實例
(1)ZoneAwareLoadBalancer.chooseServer()方法,在這裏對服務的server list選擇了一個出來
內部,一定是對每個zone,對每個機房都搞了一個LoadBalancer,所以ZoneAwareLoadBalancer內部還是基於BaseLoadBalander在工作的,封裝了多個機房,對每個機房的請求,都找每個機房自己對應的一個BaseLoadBalancer,直接調用了BaseLoadBalancer的chooseServer()方法選擇了一個server出來
public class ZoneAwareLoadBalancer<T extends Server> extends DynamicServerListLoadBalancer<T> {
@Override
public Server chooseServer(Object key) {
//區域感知邏輯禁用或只有一個區域zone
if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
logger.debug("Zone aware logic disabled or there is only one zone");
//直接調用了BaseLoadBalancer的chooseServer()方法選擇了一個server出來
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 (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.");
return super.chooseServer(key);
}
}
(2)BaseLoadBalancer的chooseServer()方法中,直接就是用的IRule來選擇了一臺服務器
public class BaseLoadBalancer extends AbstractLoadBalancer implements
PrimeConnections.PrimeConnectionListener, IClientConfigAware {
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
//直接就是用的IRule來選擇了一臺服務器
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
}
(3)用的是RibbonClientConfiguraiton中實例化的一個ZoneAvoidanceRule,調用了他的choose()方法來選擇一個server,其實是用的父類,PredicateBasedRule.choose()方法,先執行過濾規則,過濾掉一批server,根據你自己指定的filter規則,然後用round robin輪詢算法,依次獲取下一個server
public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
/**
* Method that provides an instance of {@link AbstractServerPredicate} to be used by this class.
*
*/
public abstract AbstractServerPredicate getPredicate();
/**
* Get a server by calling {@link AbstractServerPredicate#chooseRandomlyAfterFiltering(java.util.List, Object)}.
* The performance for this method is O(n) where n is number of servers to be filtered.
*/
@Override
public Server choose(Object key) {
ILoadBalancer lb = getLoadBalancer();
//根據你自己指定的filter規則先執行過濾,過濾掉一批server,然後用round robin輪詢算法,依次獲取下一個server
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
}
(4)調用AbstractServerPredicate的chooseRoundRobinAfterFiltering方法完成服務輪詢調度選取
輪詢算法其實就是把所有的server放到一個list中,然後用nextIndex.getAndIncrement() % eligible.size()取模依次返回list的索引值(0到eligible.size()-1),方法每執行一次nextIndex都會通過getAndIncrement方法累加1,從而實現依次返回不同的索引值,最終完成輪詢選擇server的效果。
public abstract class AbstractServerPredicate implements Predicate<PredicateKey> {
private final AtomicInteger nextIndex = new AtomicInteger();
/**
* Choose a server in a round robin fashion after the predicate filters a given list of servers and load balancer key.
* 在過濾後的server list中,用round robin輪詢算法,依次獲取下一個server
*/
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
//獲取符合條件的服務列表,比如ServiceA一共對應了2臺服務實例(localhost:8080和localhost:8088)
List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
if (eligible.size() == 0) {
return Optional.absent();
}
//nextIndex.getAndIncrement() % eligible.size()爲一個簡單的輪詢算法獲取索引值
return Optional.of(eligible.get(nextIndex.getAndIncrement() % eligible.size()));
}
}
總結:spring cloud與ribbon整合時的一個默認的負載均衡算法 流程圖