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