声明:

身为一个刚入门的计算机菜佬,阅读源码自然离不开优秀参考书籍和视频的引导,本篇文章的分析过程中"严重"借鉴了 翟永超 前辈的《SpringCloud微服务实战》这本书籍,在这里也向准备学习微服务的小伙伴们强烈推荐这本书,大家可以把这篇文章理解为《SpringCloud微服务实战》Ribbon部分的精简版和电子版,因为个人水平的原因,很多问题不敢妄下定论,以免误人子弟,所有书上很多内容都是精简过后直接放上去的,由于SpringCloud已经迭代到了Greenwich.SR1版本,Ribbon也和书上有了略微的差别,本篇文章的源码采用的是Ribbon最新版本,同时,因为时间原因,有很多额外的子类实现并没有完全顾上,例如PredicateBasedRule类的ZoneAvoidanceRule和AvailabilityFilteringRule 感兴趣的读者可以买《SpringCloud微服务实战》这本书细看,同时强烈推荐小马哥的微服务直播课系列《小马哥微服务实战》。

电子版及相关代码下载(欢迎Star)

Github:https://github.com/hanshuaikang/Spring-Note

微信公众号:码上marson

 

负载均衡策略

通过上面的分析,我们发现当一个请求过来时,会被拦截交给相应的负载均衡器,然后不同的负载均衡器根据不同的策略来选择合适的服务实例。在这里我们是知道Ribbon是根据不同的Rule来实现对实例的一个选择的,那么Ribbon具体提供了哪些规则供我们使用呢?通过查看Ribbon的IRule接口的实现集成关系图,我们最终可以发现,Ribbon主要提供了以下几个规则实现的。

  • RandomRule 类:该策略实现了从服务实例清单中随机选择一个服务实例的功能
  • RoundRobinRule类:该策略实现了轮询的方式从服务实例清单中依次选择服务实例的功能RetryRule
  • RetryRule类:该策略实现了具备重试机制的实例选择功能
  • WeightedResponseTimeRule类:根据权重来选择实例
  • BestAvailableRule类:选择一个最空闲的实例
  • PredicateBasedRule 类:先过滤,然后再以轮询的方式选择实例
    ...

IRule接口:



public interface IRule{

public Server choose(Object key);

public void setLoadBalancer(ILoadBalancer lb);

public ILoadBalancer getLoadBalancer();
}


AbstractLoadBalancerRule抽象类:



public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {

private ILoadBalancer lb;

@Override
public void setLoadBalancer(ILoadBalancer lb){
this.lb = lb;
}

@Override
public ILoadBalancer getLoadBalancer(){
return lb;
}
}


RandomRule类

功能:该策略实现了从服务实例清单中随机选择一个服务实例的功能。

查看代码发现具体的实例选择并没有由默认的choose(Object key)来实现,而是委托给了同类下的choose(ILoadBalancer lb, Object key)方法来完成实际的实例选择工作。



   public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;

while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();

int serverCount = allList.size();
if (serverCount == ) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}

int index = chooseRandomInt(serverCount);
server = upList.get(index);

if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}

if (server.isAlive()) {
return (server);
}

// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}

return server;

}


注:如果获取不到服务实例,则可能存在并发的bug

 

RoundRobinRule类

功能:该策略实现了轮询的方式从服务实例清单中依次选择服务实例的功能



   public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}

Server server = null;
int count = ;
while (server == null && count++ < 10) {
//reachableServers 可用的服务实例清单
List<Server> reachableServers = lb.getReachableServers();
//allServers 获取所有可用的服务列表
List<Server> allServers = lb.getAllServers();

int upCount = reachableServers.size();
int serverCount = allServers.size();

if ((upCount == ) || (serverCount == )) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}

int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);

if (server == null) {
/* Transient. */
Thread.yield();
continue;
}

if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}

// Next.
server = null;
}

if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "