Ribbon的基础知识

概述

Ribbon实现客户端的负载均衡,Feign内部是默认集成Ribbon的。本文会讲解Ribbon的常用的配置方式以及负载规则。

配置方式

配置Ribbon有两种方式,第一种是在@FeignClient中的configuration设置自定义的类

@FeignClient(value = "user", configuration = RibbonConfig.class)

Ribbon配置类RibbonConfig设置规则

@Configuration
public class RibbonConfig {
    @Bean
    public IRule ribbonRule() {
        return new RandomRule(); //随机
    }
}

第二种是在配置中定义规则(第一个值是服务名)

user.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.BestAvailableRule //空闲连接规则

常用的规则类型

BestAvailableRule(空闲连接规则)

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;
        }
    }
}

遍历所有实例,选出请求数最低的实例。

RandomRule(随机规则 )

生成随机数获取实例。

RoundRobinRule(轮询规则)

根据实例数 1-N全部轮询一遍,然后再重头开始。

RetryRule(重试规则)

实例请求时间超过maxRetryMillis(500ms)时则会返回null并进行下一次请求,重试最多会尝试10次。

WeightedResponseTimeRule(时间权重规则)

使用该规则时,WeightedResponseTimeRule内会启动一个线程DynamicServerWeightTask定期去更新每个实例的权重数,调用方法为maintainWeights。

public void maintainWeights() {
    ILoadBalancer lb = getLoadBalancer();
    if (lb == null) {
        return;
    }
    
    if (!serverWeightAssignmentInProgress.compareAndSet(false,  true))  {
        return; 
    }
    
    try {
        logger.info("Weight adjusting job started");
        AbstractLoadBalancer nlb = (AbstractLoadBalancer) lb;
        LoadBalancerStats stats = nlb.getLoadBalancerStats();
        if (stats == null) {
            // no statistics, nothing to do
            return;
        }
        double totalResponseTime = 0;
        // 第一次遍历得到所有平均请求时间的合
        for (Server server : nlb.getAllServers()) {
            // this will automatically load the stats if not in cache
            ServerStats ss = stats.getSingleServerStat(server);
            totalResponseTime += ss.getResponseTimeAvg();
        }
        // weight for each server is (sum of responseTime of all servers - responseTime)
        // so that the longer the response time, the less the weight and the less likely to be chosen
        Double weightSoFar = 0.0;
        
        // 第二次遍历把之前计算的合减去本次的平均请求时间
        List<Double> finalWeights = new ArrayList<Double>();
        for (Server server : nlb.getAllServers()) {
            ServerStats ss = stats.getSingleServerStat(server);
            double weight = totalResponseTime - ss.getResponseTimeAvg();
            weightSoFar += weight;
            finalWeights.add(weightSoFar);   
        }//这里会把权重数放到全局变量accumulatedWeights中
        setWeights(finalWeights);
    } catch (Exception e) {
        logger.error("Error calculating server weights", e);
    } finally {
        serverWeightAssignmentInProgress.set(false);
    }

}

后面在调用choose的时候就会根据最大的权重数生成一个随机数,并遍历各实例的权重数,权重数大于随机数即选择该实例。

double randomWeight = random.nextDouble() * maxTotalWeight;
//maxTotalWeight是获取accumulatedWeights的最后一个权重数
int n = 0;
for (Double d : currentWeights) {
  if (d >= randomWeight) {
    serverIndex = n;
    break;
  } else {
    n++;
  }
}
server = allList.get(serverIndex);

自定义规则

创建一个类,实现IRule即可自定义规则

public class MyRule implements IRule {

    private ILoadBalancer loadBalancer;

    @Override
    public Server choose(Object key) {
     //这里编写你规则的逻辑 List<Server> servers = loadBalancer.getAllServers(); return servers.get(0); } @Override public void setLoadBalancer(ILoadBalancer lb) { this.loadBalancer = lb; } @Override public ILoadBalancer getLoadBalancer() { return this.loadBalancer; } }
posted @ 2019-10-14 16:08  Ninon  阅读(331)  评论(0编辑  收藏  举报