Ribbion的负载均衡机制----Load Balance


Ribbion通过IRule接口调用AbstractLoadBalanceRule抽象类,这个抽象类实现了Ribbion的各种负载均衡的算法

轮询 RoundRobinRule

方法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器的下表。
假设当前有两台机器组件集群,按照轮询算法:

当前请求个数 1:1 % 2 = 1 — 获得服务器地址 xxx.xxx.xxx.1:port
当前请求个数 2:2 % 2 = 0 — 获得服务器地址 xxx.xxx.xxx.1:port
当前请求个数 3:3 % 2 = 1 — 获得服务器地址 xxx.xxx.xxx.1:port
当前请求个数 4:4 % 2 = 0 — 获得服务器地址 xxx.xxx.xxx.1:port

源码:

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(); //获取所有的server
                    int upCount = reachableServers.size();
                    int serverCount = allServers.size();
                    if (upCount != 0 && serverCount != 0) {
                        int nextServerIndex = this.incrementAndGetModulo(serverCount);//获取下次访问的server的下表----轮询方法就在这个方法中。
                        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));//此处很明显是个CAS,底层就是个轻量级的自旋锁;返回的是compareAndSwapInt(this,valueOffset,expesct,updata),防止ABA问题。
        return next;
    }

自己写代码

@Component
public class MyLB implements LoadBalancer{

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public final int getAndIncrement(){
        int current,next;
        do {
            current = this.atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
        }while (!this.atomicInteger.compareAndSet(current,next));
        System.out.println("next= "+next);
        return next;
    }

    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstancess) {

        int i = getAndIncrement() % serviceInstancess.size();

        return serviceInstancess.get(i);
    }
}

随机 RandomRule

调用Random函数随机返回一个服务器地址

代码

public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            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 == 0) {
                    return null;
                }

                int index = this.chooseRandomInt(serverCount);//这里进行随机选择一个index
                server = (Server)upList.get(index);
                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }
protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);//这里进行随机选择
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

重试 RetryRule

Retry规则会先按照轮询进行服务获取,获取失败后会在指定的响应时间内重试

 public RetryRule(IRule subRule) {
        this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
    }

public RetryRule(IRule subRule, long maxRetryMillis) {
    this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
    this.maxRetryMillis = maxRetryMillis > 0L ? maxRetryMillis : 500L;
}
//默认是按照轮询方式进行选择
public Server choose(ILoadBalancer lb, Object key) {
        long requestTime = System.currentTimeMillis();
        long deadline = requestTime + this.maxRetryMillis;
        Server answer = null;
        answer = this.subRule.choose(key);
        //默认通过上一行代码进行轮询选择,轮询如果失败进入下面的代码;下面的代码通过InterruptTask进行选择出requestTime + this.maxRetryMillis- System.currentTimeMillis()最小的服务器返回。也就是找响应时间最短的服务器。
        if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline) {
            InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());

            while(!Thread.interrupted()) {
                answer = this.subRule.choose(key);
                if (answer != null && answer.isAlive() || System.currentTimeMillis() >= deadline) {
                    break;
                }

                Thread.yield();
            }

            task.cancel();
        }

        return answer != null && answer.isAlive() ? answer : null;
    }

加权响应 WeightedResponseTimeRule

获取响应速度最快的实例

代码

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

            while(server == null) {
                List<Double> currentWeights = this.accumulatedWeights;
                if (Thread.interrupted()) {
                    return null;
                }

                List<Server> allList = lb.getAllServers();
                int serverCount = allList.size();
                if (serverCount == 0) {
                    return null;
                }

                int serverIndex = 0;
                double maxTotalWeight = currentWeights.size() == 0 ? 0.0D : (Double)currentWeights.get(currentWeights.size() - 1);
                if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
                    double randomWeight = this.random.nextDouble() * maxTotalWeight;
                    int n = 0;

                    for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
                        Double d = (Double)var13.next();
                        if (d >= randomWeight) {
                            serverIndex = n;
                            break;
                        }
                    }

                    server = (Server)allList.get(serverIndex);
                } else {
                    server = super.choose(this.getLoadBalancer(), key);
                    if (server == null) {
                        return server;
                    }
                }

                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                }
            }

            return server;
        }
    }

最佳可用 BestAvailableRule

优先过滤掉由多次访问故障的服务器,选择并发量最小的服务器

代码

public Server choose(Object key) {
        if (this.loadBalancerStats == null) {
            return super.choose(key);
        } else {
            List<Server> serverList = this.getLoadBalancer().getAllServers();
            int minimalConcurrentConnections = 2147483647;
            long currentTime = System.currentTimeMillis();
            Server chosen = null;
            Iterator var7 = serverList.iterator();

            while(var7.hasNext()) {
                Server server = (Server)var7.next();
                ServerStats serverStats = this.loadBalancerStats.getSingleServerStat(server);
                if (!serverStats.isCircuitBreakerTripped(currentTime)) {
                    int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);//获取连接数
                    if (concurrentConnections < minimalConcurrentConnections) {
                        minimalConcurrentConnections = concurrentConnections;//更新连接数,去掉不可用服务器
                        chosen = server;//在可用服务器中用next获取返回
                    }
                }
            }

            if (chosen == null) {
                return super.choose(key);
            } else {
                return chosen;
            }
        }
    }

AvailabilityFilteringRule

先过滤到故障实例,再选择并发较小的实例

代码

public class AvailabilityFilteringRule extends PredicateBasedRule {
    private AbstractServerPredicate predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, (IClientConfig)null)).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();

    public AvailabilityFilteringRule() {
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
        this.predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, clientConfig)).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
    }

    @Monitor(
        name = "AvailableServersCount",
        type = DataSourceType.GAUGE
    )
    public int getAvailableServersCount() {
        ILoadBalancer lb = this.getLoadBalancer();
        List<Server> servers = lb.getAllServers();
        return servers == null ? 0 : Collections2.filter(servers, this.predicate.getServerOnlyPredicate()).size();
    }

    public Server choose(Object key) {
        int count = 0;

        for(Server server = this.roundRobinRule.choose(key); count++ <= 10; server = this.roundRobinRule.choose(key)) {
            if (this.predicate.apply(new PredicateKey(server))) {
                return server;
            }
        }

        return super.choose(key);
    }

    public AbstractServerPredicate getPredicate() {
        return this.predicate;
    }
}

ZoneAvoidanceRule

public class ZoneAvoidanceRule extends PredicateBasedRule {
    private static final Random random = new Random();
    private CompositePredicate compositePredicate;

    public ZoneAvoidanceRule() {
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
        this.compositePredicate = this.createCompositePredicate(zonePredicate, availabilityPredicate);
    }

    private CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {
        return CompositePredicate.withPredicates(new AbstractServerPredicate[]{p1, p2}).addFallbackPredicate(p2).addFallbackPredicate(AbstractServerPredicate.alwaysTrue()).build();
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this, clientConfig);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this, clientConfig);
        this.compositePredicate = this.createCompositePredicate(zonePredicate, availabilityPredicate);
    }

    static Map<String, ZoneSnapshot> createSnapshot(LoadBalancerStats lbStats) {
        Map<String, ZoneSnapshot> map = new HashMap();
        Iterator var2 = lbStats.getAvailableZones().iterator();

        while(var2.hasNext()) {
            String zone = (String)var2.next();
            ZoneSnapshot snapshot = lbStats.getZoneSnapshot(zone);
            map.put(zone, snapshot);
        }

        return map;
    }

    static String randomChooseZone(Map<String, ZoneSnapshot> snapshot, Set<String> chooseFrom) {
        if (chooseFrom != null && chooseFrom.size() != 0) {
            String selectedZone = (String)chooseFrom.iterator().next();
            if (chooseFrom.size() == 1) {
                return selectedZone;
            } else {
                int totalServerCount = 0;

                String zone;
                for(Iterator var4 = chooseFrom.iterator(); var4.hasNext(); totalServerCount += ((ZoneSnapshot)snapshot.get(zone)).getInstanceCount()) {
                    zone = (String)var4.next();
                }

                int index = random.nextInt(totalServerCount) + 1;
                int sum = 0;
                Iterator var6 = chooseFrom.iterator();

                while(var6.hasNext()) {
                    String zone = (String)var6.next();
                    sum += ((ZoneSnapshot)snapshot.get(zone)).getInstanceCount();
                    if (index <= sum) {
                        selectedZone = zone;
                        break;
                    }
                }

                return selectedZone;
            }
        } else {
            return null;
        }
    }

    public static Set<String> getAvailableZones(Map<String, ZoneSnapshot> snapshot, double triggeringLoad, double triggeringBlackoutPercentage) {
        if (snapshot.isEmpty()) {
            return null;
        } else {
            Set<String> availableZones = new HashSet(snapshot.keySet());
            if (availableZones.size() == 1) {
                return availableZones;
            } else {
                Set<String> worstZones = new HashSet();
                double maxLoadPerServer = 0.0D;
                boolean limitedZoneAvailability = false;
                Iterator var10 = snapshot.entrySet().iterator();

                while(true) {
                    while(var10.hasNext()) {
                        Entry<String, ZoneSnapshot> zoneEntry = (Entry)var10.next();
                        String zone = (String)zoneEntry.getKey();
                        ZoneSnapshot zoneSnapshot = (ZoneSnapshot)zoneEntry.getValue();
                        int instanceCount = zoneSnapshot.getInstanceCount();
                        if (instanceCount == 0) {
                            availableZones.remove(zone);
                            limitedZoneAvailability = true;
                        } else {
                            double loadPerServer = zoneSnapshot.getLoadPerServer();
                            if ((double)zoneSnapshot.getCircuitTrippedCount() / (double)instanceCount < triggeringBlackoutPercentage && loadPerServer >= 0.0D) {
                                if (Math.abs(loadPerServer - maxLoadPerServer) < 1.0E-6D) {
                                    worstZones.add(zone);
                                } else if (loadPerServer > maxLoadPerServer) {
                                    maxLoadPerServer = loadPerServer;
                                    worstZones.clear();
                                    worstZones.add(zone);
                                }
                            } else {
                                availableZones.remove(zone);
                                limitedZoneAvailability = true;
                            }
                        }
                    }

                    if (maxLoadPerServer < triggeringLoad && !limitedZoneAvailability) {
                        return availableZones;
                    }

                    String zoneToAvoid = randomChooseZone(snapshot, worstZones);
                    if (zoneToAvoid != null) {
                        availableZones.remove(zoneToAvoid);
                    }

                    return availableZones;
                }
            }
        }
    }

    public static Set<String> getAvailableZones(LoadBalancerStats lbStats, double triggeringLoad, double triggeringBlackoutPercentage) {
        if (lbStats == null) {
            return null;
        } else {
            Map<String, ZoneSnapshot> snapshot = createSnapshot(lbStats);
            return getAvailableZones(snapshot, triggeringLoad, triggeringBlackoutPercentage);
        }
    }

    public AbstractServerPredicate getPredicate() {
        return this.compositePredicate;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值