# Ribbon 负载均衡

Ribbon Spring Cloud 体系中的客户端负载均衡器,Ribbon 针对负载均衡提供了多种策略。

相应的类图如下:

部分类描述如下表:

策略类 描述
IRule 所有策略的最上层接口。规范了负载均衡策略方法实现。
AbstractLoadBalancerRule 所有策略的最上层抽象。提供了 ILoadBalancer 注入。
RandomRule 随机策略。随机选择存活的 server 实例。
RoundRobinRule 轮询策略。按顺序循环轮询存活的 server 实例。
RetryRule 重试策略。装饰者模式委派 RoundRobinRule 获取服务实例,如果实例死亡,在指定时间内,不断通过 RoundRobinRule尝试获取新的存活的服务实例。
BestAvailableRule 最好可用策略。遍历所有服务实例,找到 server 断路器未打开的服务实例,从其中选出并发链接最低的 server,如果找不到使用 RoundRobinRule 进行娄底。
AvailabilityFilteringRule 可用过滤策略。通过 RoundRobinRule 结合 AbstractServerPredicate 过滤断言进行服务实例过滤,最多过滤10次,如果还是无法获取到服务实例,使用 RoundRobinRule 进行娄底。
WeightedResponseTimeRule 响应时间权重策略。提供有专门的线程去统计服务实例的响应时间,并计算权重,然后根据权重进行服务实例获取,如果无法获取到服务实例,使用RoundRobinRule 进行娄底。
ZoneAvoidanceRule 区域权衡策略。和 AvailabilityFilteringRule 类似,不过其通过 装饰者模式 和 组合模式,通过一系列的复杂断言来过滤服务实例。

# RandomRule 随机策略

# 类结构

# 关键代码

public class RandomRule extends AbstractLoadBalancerRule {
	public Server choose(ILoadBalancer lb, Object key) {
		while (server == null) {
		    // 获取所有状态为 up 且,可达的服务列表
			List<Server> upList = lb.getReachableServers();
			// 获取所有服务列表,无论是否可达
	        List<Server> allList = lb.getAllServers();

	        // 所有服务实例总数
	        int serverCount = allList.size();
	        // 根据服务总数获取随机数
	        int index = chooseRandomInt(serverCount);
	        // 从可达的 up 状态的服务实例列表中,根据随机 index 获取服务实例
	        server = upList.get(index);
	        // 如果服务存活,返回实例名
	        if (server.isAlive()) {
	        	return (server);
	        }
	    }
	}

	// 随机数获取
	protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }
}

# RetryRule 重试策略

# 类结构

# 关键代码

public class RetryRule extends AbstractLoadBalancerRule {
	// 娄底策略:轮询策略
	IRule subRule = new RoundRobinRule();

	// 在指定时间内不断尝试获取服务实例。默认:500 ms
	long maxRetryMillis = 500;

	public Server choose(ILoadBalancer lb, Object key) {
		// 当前请求时间
		long requestTime = System.currentTimeMillis();
		// 如果第一次获取到,在时间未到达 deadline 时,不断进行重试操作
		long deadline = requestTime + maxRetryMillis;

		// 通过轮询获取一个服务实例
		Server answer = null;
		answer = subRule.choose(key);

		// 两个条件满足,进入到重试逻辑
		// 条件一: 轮询获取到的实例为 null 或者 实例死亡
		// 条件二: 时间在允许重试的范围内
		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)) {
				    // 将重试线程重新归入就绪状态,模拟:线程短暂暂停
					Thread.yield();
				}else{
				    // 获取到实例,跳出循环
					break;
				}
			}

			// 正常获取到实例,手动调用结束定时任务
			task.cancel();
		}

		// 无论是正常结束,还是超时结束,最终都要进行返回
		if ((answer == null) || (!answer.isAlive())) {
			return null;
		} else {
			return answer;
		}
	}
}

逻辑图如下:

# ZoneAvoidanceRule 区域权衡策略

# 类结构

# 类组装图

# 父类 PredicateBasedRule 关键代码

ZoneAvoidanceRule 父类 PredicateBasedRulechoose 方法进行了覆盖,将服务实例的选择,委派给了 AbstractServerPredicate 实现。

public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {

	// 该方法由其子类实现,如:ZoneAvoidanceRule
	public abstract AbstractServerPredicate getPredicate();

	@Override
    public Server choose(Object key) {
    	ILoadBalancer lb = getLoadBalancer();
    	// 服务实例的获取,由 AbstractServerPredicate#chooseRoundRobinAfterFiltering 来完成
        Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
        if (server.isPresent()) {
            return server.get();
        } else {
            return null;
        }       
    }
}

# CompositePredicate 关键代码

# 类图结构

# CompositePredicate#chooseRoundRobinAfterFiltering 服务实例获取时序图

chooseRoundRobinAfterFiltering 方法是在经过断言过滤之后,如果有多个实例,则通过轮询的方式获取实例

首先来看看 ZoneAvoidanceRule 组装的 CompositePredicate 。其由如下两个过滤链组成

  • AbstractServerPredicate delegate

    该过滤链由: ZoneAvoidancePredicate + AvailabilityPredicate 组成

  • List<AbstractServerPredicate> fallbacks

    该过滤链由: AvailabilityPredicate + AbstractServerPredicate.alwaysTrue() 空实现组成

public class ZoneAvoidanceRule extends PredicateBasedRule {
	
	// 组合断言
	private CompositePredicate compositePredicate;

	public ZoneAvoidanceRule() {
        super();
        // 组合断言
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
    }

    // 组装 CompositePredicate
    private CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {
        return CompositePredicate.withPredicates(p1, p2)
                             .addFallbackPredicate(p2)
                             .addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
                             .build();
        
    }
}

# 过滤执行操作

精彩内容推送,请关注公众号!
最近更新时间: 6/2/2020, 4:47:31 PM