// spring-cloud-netfix-core
//RibbonLoadBalancerClient //ribbonClinet 具体的执行类 LoadBalancerClient → ServiceInstanceChooser包含选择服务实例方法没用上,最终使用ILoadBalancer的子类方法
//RibbonClientConfiguration // 自动装载ZoneAwareLoadBalancer 负载均衡默认策略
// RibbonLoadBa lancerContext //上下文--包含ribbon重试相关 通过SpringClientFactory得到
// com.netflix.ribbon:ribbon-loadbalancer
//DynamicServerListLoadBalancer dd = new DynamicServerListLoadBalancer();
//ZoneAwareLoadBalancer
// 父类ILoadBalancer → AbstractLoadBalancer → BaseLoadBalancer → DynamicServerListLoadBalancer → ZoneAwareLoadBalancer 服务器实例选择和管理策略
// ZoneAwareLoadBalancer的chooseServer在zone数量不大于1的情况下会执行BaseLoadBalancer的chooseServer,实际由IRule的子类来执行,默认是RoundRobinRule
// RoundRobinRule的choose来执,默认是常用的线性负载均衡策略 IRule → AbstractLoadBalancerRule → RoundRobinRule
// IRule 有多个实现类 RoundRobinRule(线性轮休)、RetryRule(通过线性轮休重试)、RandomRule(随机)、ZoneAvoidanceRule、WeightedResponseTimeRule(响应时间权重)
// ClientConfigEnabledRoundRobinRule(高级策略实现) BestAvailableRule(loanBalancerStats找出最空闲,loanBalancerStats为空使用线性轮休【继承ClientConfigEnabledRoundRobinRule】)
//PredicateBasedRule(通过实现的策略apply等来过滤,集成) AvailabilityFilteringRule继承PredicateBasedRule(apply实现为,断路器是否打开、并发数大于阈值) ZoneAvoidanceRule 默认实现,多区域rule
//RibbonClientConfiguration 和 EurekaRibbonClientConfiguration 关联注入类PropertiesFactory(再议)
//ConfigurationBasedServerList
// org.springframework.cloud:spring-cloud-netflix-eureka-client
//EurekaRibbonClientConfiguration 初始化ribbonServerList 触发DiscoveryEnabledNIWSServerList的obtainServersViaDiscovery通过eurekaClientProvider的EurekaClient
// 需求方RibbonClientConfiguration初始化的时候注入了ServerList 用于给 ZoneAwareLoadBalancer实例化 severlist
//DiscoveryManager.getInstance().shutdownComponent(); // LookupService → EurekaClient → com.netflix.discovery.DiscoveryClient→ CloudEurekaClient
//EurekaClientAutoConfiguration初始化了 EurekaDiscoveryClient org.springframework.cloud.client.discovery.DiscoveryClient → EurekaDiscoveryClient
//相关注解
// @ConditionalOnMissingBean 作用在方法 list上,list为null返回true,否则返回false
// @VisibleForTesting 用来测试私有private方法的注解
// @Import
RoundRobinRule的choose的方法
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if (upCount != 0 && serverCount != 0) {
int nextServerIndex = this.incrementAndGetModulo(serverCount);
server = (Server)allServers.get(nextServerIndex);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) {
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;
} while(!this.nextServerCyclicCounter.compareAndSet(current, next));
return next;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}