美文网首页
SpringCloud系列之负载均衡Ribbon·6-负载均衡策

SpringCloud系列之负载均衡Ribbon·6-负载均衡策

作者: 那钱有着落吗 | 来源:发表于2021-04-02 10:06 被阅读0次
image.png

我们分别看一下关于RandomRule和RoundRobinRule类的源码

  • 1.RandomRule:

image.png
image.png
  • 2.RoundRobinRule:

image.png

两者有两个区别:1.策略不一致,一个是轮训一个是随机 2.随机策略如果查询不到服务就会一直的查询,而轮训是有10次的限制,过了就不再查询

  • 3.BestAvailableRule

image.png

如果当前这个负载均衡状态为空的话,就调用父类的选择,然后点进去看:


image.png

就会发现这个BestAvailableRule类是继承AbstractLoadBalancerRule,他的基础就是上一点钟的RoundRobinRule轮训的策略。

然后:

List<Server> serverList = getLoadBalancer().getAllServers();
        int minimalConcurrentConnections = Integer.MAX_VALUE;
        long currentTime = System.currentTimeMillis();
        Server chosen = null;
        for (Server server: serverList) {
            ServerStats serverStats = loadBalancerStats.getSingleServerStat(server);
            if (!serverStats.isCircuitBreakerTripped(currentTime)) {
                int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
                if (concurrentConnections < minimalConcurrentConnections) {
                    minimalConcurrentConnections = concurrentConnections;
                    chosen = server;
                }
            }
        }

获取所有的服务,然后获取当前时间,开始遍历所有的服务:

我们再看下这个代码:

  ServerStats serverStats = loadBalancerStats.getSingleServerStat(server);

点进去看到这个代码:

private ServerStats getServerStats(Server server) {
        try {
            return serverStatsCache.get(server);
        } catch (ExecutionException e) {
            ServerStats stats = createServerStats(server);
            serverStatsCache.asMap().putIfAbsent(server, stats);
            return serverStatsCache.asMap().get(server);
        }
    }

会发现是否可以返回这个服务的缓存,如果有异常则初始化一个server的状态并返回。

private ServerStats createServerStats(Server server) {
        ServerStats ss = new ServerStats(this);
        //configure custom settings
        ss.setBufferSize(1000);
        ss.setPublishInterval(1000);                    
        ss.initialize(server);
        return ss;        
    }

最关键是这段代码:

serverStats.isCircuitBreakerTripped(currentTime)

再往下看:

public boolean isCircuitBreakerTripped(long currentTime) {
        long circuitBreakerTimeout = getCircuitBreakerTimeout();
        if (circuitBreakerTimeout <= 0) {
            return false;
        }
        return circuitBreakerTimeout > currentTime;
    }
private long getCircuitBreakerTimeout() {
        long blackOutPeriod = getCircuitBreakerBlackoutPeriod();
        if (blackOutPeriod <= 0) {
            return 0;
        }
        return lastConnectionFailedTimestamp + blackOutPeriod;
    }
private long getCircuitBreakerBlackoutPeriod() {
        int failureCount = successiveConnectionFailureCount.get();
        int threshold = connectionFailureThreshold.get();
        if (failureCount < threshold) {
            return 0;
        }
        int diff = (failureCount - threshold) > 16 ? 16 : (failureCount - threshold);
        int blackOutSeconds = (1 << diff) * circuitTrippedTimeoutFactor.get();
        if (blackOutSeconds > maxCircuitTrippedTimeout.get()) {
            blackOutSeconds = maxCircuitTrippedTimeout.get();
        }
        return blackOutSeconds * 1000L;
    }

获取到失败的链接,和失败的阈值,如果失败链接数小于阈值则直接返回0,否则计算一个差值,然后根据这个差值计算出一个熔断需要时间段,然后返回。

返回之后通过用 之前失败的时间+熔断需要时间段 得出一个最终熔断的时间。

然后就到这段代码:

if (!serverStats.isCircuitBreakerTripped(currentTime)) {
                int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
                if (concurrentConnections < minimalConcurrentConnections) {
                    minimalConcurrentConnections = concurrentConnections;
                    chosen = server;
                }
            }

这个判断意思就是如果没有到熔断时间的话我们就进入下面的逻辑:

获取这台服务当前的连接数,如果这个连接数小于minimalConcurrentConnections变量,则minimalConcurrentConnections变量赋值为该服务的连接数,然后chosen为当前服务,这段意思就是 遍历所有的服务,找到最小连接数的服务。

读到这里,我们就知道了,这个策略在轮训的策略基础上,找到服务器中最小连接数的服务。

  • 4.RetryRule


IRule subRule = new RoundRobinRule();
public Server choose(ILoadBalancer lb, Object key) {
        long requestTime = System.currentTimeMillis();
        long deadline = requestTime + maxRetryMillis;

        Server answer = null;

        answer = subRule.choose(key);

        if (((answer == null) || (!answer.isAlive()))
                && (System.currentTimeMillis() < deadline)) {

            InterruptTask task = new InterruptTask(deadline
                    - System.currentTimeMillis());

            while (!Thread.interrupted()) {
                answer = subRule.choose(key);

                if (((answer == null) || (!answer.isAlive()))
                        && (System.currentTimeMillis() < deadline)) {
                    /* pause and retry hoping it's transient */
                    Thread.yield();
                } else {
                    break;
                }
            }

            task.cancel();
        }

        if ((answer == null) || (!answer.isAlive())) {
            return null;
        } else {
            return answer;
        }
    }

从源码中我们可以看出RetryRule的实现是基于一个基础的策略,默认是RoundRobinRule,我们也可以修改成别的策略。

其实RetryRule就是在基础的策略上加了一个Retry的逻辑,跟着源码看,首先拿到最大的重试时间,然后计算出死亡时间,然后在死亡时间之前进行重试。

InterruptTask task = new InterruptTask(deadline
- System.currentTimeMillis());

这块的代码是在到了死亡时间就启动一个定时器,中断当前线程,而在死亡时间之前如果能获取到服务,则取消掉这个定时器。

  • 5.WeightedResponseTimeRule

这个Rule继承自RoundRibbonRule,他会根据服务节点的响应时间计算权重,响应时间越长权重就越低,响应越快则权重越高,权重的高低决定了机器被选中概率的高低。也就是说,响应时间越小的机器,被选中的概率越大。

image.png

由于服务器刚启动的时候,对各个服务节点采样不足,因此会采用轮询策略,当积累到一定的样本时候,会切换到WeightedResponseTimeRule模式。关于权重的计算方式,请大家参考源码阅读视频。

  • 6.AvailabilityFilteringRule

这个规则底层依赖RoundRobinRule来选取节点,但并非来者不拒,它也是有一些底线的,必须要满足它的最低要求的节点才会被选中。如果节点满足了要求,无论其响应时间或者当前并发量是什么,都会被选中。

image.png

每次AvailabilityFilteringRule(简称AFR)都会请求RobinRule挑选一个节点,然后对这个节点做以下两步检查:
 是否处于熔断状态(熔断是Hystrix中的知识点,后面章节会讲到,这里大家可以把熔断当做服务不可用)
 节点当前的active请求连接数超过阈值,超过了则表示节点目前太忙,不适合接客
如果被选中的server不幸挂掉了检查,那么AFR会自动重试(次数最多10次),让RobinRule重新选择一个服务节点。

  • 7.ZoneAvoidanceRule

这个过滤器包含了组合过滤条件,分别是Zone级别和可用性级别。

image.png

 Zone Filter: 在Eureka注册中一个服务节点有Zone, Region和URL三个身份信息,其中Zone可以理解为机房大区(未指定则由Eureka给定默认值),而这里会对这个Zone的健康情况过滤其下面所有服务节点。
 可用性过滤:这里和AvailabilityFilteringRule的验证非常像,会过滤掉当前并发量较大,或者处于熔断状态的服务节点。

相关文章

网友评论

      本文标题:SpringCloud系列之负载均衡Ribbon·6-负载均衡策

      本文链接:https://www.haomeiwen.com/subject/upxnhltx.html