【源码】Spring Cloud —— Ribbon 2 ILoadBalancer

前言

上一章节主要介绍了:

  • RibbonClientConfigurationRegistrar,注册对应 RibbonClient 的组件到容器中,由 SpringClientFactory 创建管理对应的 上下文
  • LoadBalancerClient负载均衡 顶层接口,底层委托给 ILoadBalancer 实现

本章节结合源码介绍 ILoadBalancer 接口及其部分实现类

版本

Spring Cloud Netflix 版本:2.2.3.RELEASE

ILoadBalancer

public interface ILoadBalancer {

	// 服务实例添加
	public void addServers(List<Server> newServers);
	
	// 筛选服务实例
	public Server chooseServer(Object key);
	
	// 标记服务下线
	public void markServerDown(Server server);
	
	// @Deprecated,见下面两个方法
	@Deprecated
	public List<Server> getServerList(boolean availableOnly);

	// 存活服务列表获取
    public List<Server> getReachableServers();

    // 所有服务列表获取
	public List<Server> getAllServers();
}

顶层接口,由 com.netflix.ribbon 依赖提供,定义了 服务实例获取、服务列表获取 等相关方法

AbstractLoadBalancer

public abstract class AbstractLoadBalancer implements ILoadBalancer {
    
    // 服务实例状态枚举
    public enum ServerGroup{
        ALL,
        STATUS_UP,
        STATUS_NOT_UP        
    }
        
   // chooseServer 委托给 chooseServer(null)
    public Server chooseServer() {
    	return chooseServer(null);
    }

	// 根据状态筛选服务实例列表
    public abstract List<Server> getServerList(ServerGroup serverGroup);
    
    // LoadBalancerStats:LoadBalancer 相关统计封装
    public abstract LoadBalancerStats getLoadBalancerStats();    
}

ILoadBalancer 的抽象实现

BaseLoadBalancer

AbstractLoadBalancer 的实现类,它维护了 服务列表、服务状态 等属性

	// 所有服务实例列表
    protected volatile List<Server> allServerList = Collections
            .synchronizedList(new ArrayList<Server>());
   
   // 所有有效服务实例列表
    protected volatile List<Server> upServerList = Collections
            .synchronizedList(new ArrayList<Server>());

	------------------------------------------------------

	// 服务实例状态统计
	protected LoadBalancerStats lbStats;

	------------------------------------------------------

	// 负载均衡策略
	protected IRule rule = DEFAULT_RULE;

继续解读核心方法的实现

addServers(List newServers)

	// 把所有服务实例放到一个新的集合里再 set
	public void addServers(List<Server> newServers) {
        if (newServers != null && newServers.size() > 0) {
            try {
                ArrayList<Server> newList = new ArrayList<Server>();
                newList.addAll(allServerList);
                newList.addAll(newServers);
                setServersList(newList);
            } catch (Exception e) {
                
                // ...
                
            }
        }
    }

服务实例的添加

chooseServer(Object key)

	public Server chooseServer(Object key) {
		// 计数
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
            	// IRule#choose
                return rule.choose(key);
            } catch (Exception e) {
                
                // ...
                
            }
        }
    }

服务实例的选取最终由 负载均衡 策略实例 IRule 实现

markServerDown(Server server)

	public void markServerDown(Server server) {
        if (server == null || !server.isAlive()) {
            return;
        }

		// 下线
        server.setAlive(false);

		// 事件发布
        notifyServerStatusChangeListener(singleton(server));
    }

服务实例标记下线

getReachableServers() & getAllServers()

	@Override
    public List<Server> getReachableServers() {
        return Collections.unmodifiableList(upServerList);
    }

    @Override
    public List<Server> getAllServers() {
        return Collections.unmodifiableList(allServerList);
    }

返回维护的对应属性即可

getServerList(ServerGroup serverGroup)

	public List<Server> getServerList(ServerGroup serverGroup) {
        switch (serverGroup) {
        case ALL:
            return allServerList;
        case STATUS_UP:
            return upServerList;

		// STATUS_NOT_UP = ALL - STATUS_UP
        case STATUS_NOT_UP:
            ArrayList<Server> notAvailableServers = new ArrayList<Server>(
                    allServerList);
            ArrayList<Server> upServers = new ArrayList<Server>(upServerList);
            notAvailableServers.removeAll(upServers);
            return notAvailableServers;
        }
        return new ArrayList<Server>();
    }

根据状态筛选 服务实例 列表

DynamicServerListLoadBalancer

拓展了 BaseLoadBalancer,提供了 动态更新 服务列表的能力

ZoneAwareLoadBalancer

ZoneAwareLoadBalancer 继承了 DynamicServerListLoadBalancer,重点是拓展了 chooseServer 方法,提供了 区域亲和 的实现

	public Server chooseServer(Object key) {
        if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
        	// 区域亲和关闭,或可用服务实例 <= 1
            return super.chooseServer(key);
        }
        Server server = null;
        try {
            LoadBalancerStats lbStats = getLoadBalancerStats();
	
			// 获取区域快照
            Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
            
            // 从动态配置获取 平均负载 属性
            if (triggeringLoad == null) {
                triggeringLoad = DynamicPropertyFactory.getInstance().getDoubleProperty(
                        "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".triggeringLoadPerServerThreshold", 0.2d);
            }

			// 从动态配置获取 实例故障率 属性
            if (triggeringBlackoutPercentage == null) {
                triggeringBlackoutPercentage = DynamicPropertyFactory.getInstance().getDoubleProperty(
                        "ZoneAwareNIWSDiscoveryLoadBalancer." + this.getName() + ".avoidZoneWithBlackoutPercetage", 0.99999d);
            }

			// 根据对应属性获取可用区域集合
            Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());

			// ZoneAvoidanceRule.randomChooseZone 从可用区域集合随机选择一个 zone
            if (availableZones != null &&  availableZones.size() < zoneSnapshot.keySet().size()) {
                String zone = ZoneAvoidanceRule.randomChooseZone(zoneSnapshot, availableZones);

                if (zone != null) {

					// 根据 zone 获取对应的 BaseLoadBalancer 
                    BaseLoadBalancer zoneLoadBalancer = getLoadBalancer(zone);

					// BaseLoadBalancer#chooseServer 获取服务实例
                    server = zoneLoadBalancer.chooseServer(key);
                }
            }
        } catch (Exception e) {
            
            // ...
            
        }
        if (server != null) {
            return server;
        } else {
            logger.debug("Zone avoidance logic is not invoked.");
            return super.chooseServer(key);
        }
    }

	------------------ getLoadBalancer ------------------

	BaseLoadBalancer getLoadBalancer(String zone) {
        zone = zone.toLowerCase();
        BaseLoadBalancer loadBalancer = balancers.get(zone);

		// 每个区域对应的 BaseLoadBalancer 缓存在 balancers
        if (loadBalancer == null) {

			// IRule 默认与外部实例相同,即默认 ZoneAvoidanceRule
        	IRule rule = cloneRule(this.getRule());
            loadBalancer = new BaseLoadBalancer(this.getName() + "_" + zone, rule, this.getLoadBalancerStats());
            BaseLoadBalancer prev = balancers.putIfAbsent(zone, loadBalancer);
            if (prev != null) {
            	loadBalancer = prev;
            }
        } 
        return loadBalancer;        
    }
  • 从实例状态属性 LoadBalancerStats lbStats 中获取 区域快照
  • 动态配置 获取两个属性:平均负载、实例故障率
  • 根据上述属性获取 可用区域集合
  • ZoneAvoidanceRule 随机选择一个区域 zone
  • 获取该 zone 对应的 BaseLoadBalancer
  • 最终 服务实例 的获取由 BaseLoadBalancer#chooseServer 实现,上文已解读,该行为将委托给负载均衡策略实例 IRule 实现

同时,ZoneAwareLoadBalancerSpring Cloud 默认提供的 负载均衡 组件实例

	// RibbonClientConfiguration
	@Bean
	@ConditionalOnMissingBean
	public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
			ServerList<Server> serverList, ServerListFilter<Server> serverListFilter,
			IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
		if (this.propertiesFactory.isSet(ILoadBalancer.class, name)) {
			return this.propertiesFactory.get(ILoadBalancer.class, config, name);
		}
		return new ZoneAwareLoadBalancer<>(config, rule, ping, serverList,
				serverListFilter, serverListUpdater);
	}

总结

ILoadBalancer 封装了 Ribbon负载均衡 的实现,提供了诸如 服务实例获取、服务列表的维护 等功能,其中 服务实例 的获取最终由 负载均衡 策略实例 IRule 来实现,下章节结合源码解读 IRule 相关接口和实现类

上一篇:【源码】Spring Cloud —— Ribbon 1 RibbonClientConfigurationRegistrar LoadBalancerClient 相关

下一篇:【源码】Spring Cloud —— Ribbon 3 IRule

参考

《Spring Cloud 微服务架构进阶》 —— 朱荣鑫 张天 黄迪璇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值