Netflix Ribbon - SpringCloud整合Ribbon - 默认负载均衡算法选择Server

96 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


SpringCloud整合Ribbon - 默认负载均衡算法选择Server

ZoneAwareLoadBalancer impl DynamicServerListLoadBalancer impl BaseLoadBalancer

通过LoadBalancer从一个服务对应的server list中选择一个server出来,保持负载均衡,将请求均匀的发送各个服务器上去

LoadBalancer.chooseServer()方法,通过内置的负载均衡算法,选择一个server

ZoneAwareLoadBalancer,机房概念,多机房的话,可以感知到多机房的,将一个机房里的请求,转发至同机房里部署的其他的服务实例。内部每个zone,每个机房对应一个LoadBalancer。

ZoneAwareLoadBalancer内部基于BaseLoadBalander工作,封装多个机房,对每个机房的请求,找每个机房对应的BaseLoadBalancer,调用BaseLoadBalancer.chooseServer()方法选择了一个server。

BaseLoadBalancer.chooseServer()方法内部通过策略模式调用对应的IRule封装的负载均衡算法,选择一台服务器。

策略模式:封装算法

IRule代表封装的负载均衡的算法

- 上下文角色(Context):用来操作策略的上下文环境,屏蔽客户端对策略直接访问;
- 抽象策略角色(Strategy):规定策略的行为;
- 具体策略角色(ConcreteStrategy):具体的策略实现;


ZoneAvoidanceRule -> PredicateBasedRule -> ClientConfigEnabledRoundRobinRule -> IRule

IRule用的是RibbonClientConfiguraiton中实例化的ZoneAvoidanceRule。


package com.netflix.loadbalancer;

public interface IRule{

    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

ZoneAvoidanceRule提供CompositePredicate,调用父类PredicateBasedRule.choose()方法,通过CompositePredicate执行过滤规则,过滤掉一批server,然后用round robin轮询算法,依次获取下一个server

// PredicateBasedRule.java

@Override
public Server choose(Object key) {
    ILoadBalancer lb = getLoadBalancer();
    Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
    if (server.isPresent()) {
        return server.get();
    } else {
        return null;
    }       
}

服务实例列表(server list)

192.168.1.2:7071

192.168.1.2:7070

CompositePredicate:从服务实例列表中,第一台开始,每台机器访问一次,依次循环往复

CompositePredicate -> AbstractServerPredicate -> Predicate
// ((CompositePredicate)AbstractServerPredicate).chooseRoundRobinAfterFiltering

public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
    List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
    if (eligible.size() == 0) {
        return Optional.absent();
    }
    return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}
// ((CompositePredicate)AbstractServerPredicate).incrementAndGetModulo
// round robin轮询算法

private int incrementAndGetModulo(int modulo) {
    for (;;) {
        int current = nextIndex.get();
        int next = (current + 1) % modulo;
        if (nextIndex.compareAndSet(current, next) && current < modulo)
            return current;
    }
}

modulo:2,代表的是当前服务实例数量。

AbstractServerPredicate.incrementAndGetModulo()方法,采用round robin轮询算法,依次遍历选择server list中的每一台server