[Spring Cloud系列]Ribbon服务更新

之前,猿Why认为应用中集成Consul进行服务注册与服务发现。那么,应用中的服务列表应当也是由Consul模块进行更新。为了给同事一个准确的回答,再次看了看源码后,发现服务列表的更新,并不是由服务注册中心和服务发现模块来处理的(比如Consul、Eureka)。

首先,服务注册中心的概念是抽象的,所以服务列表的更新必然不是由服务发现的具体实现方式(Consul、Eureka)来实现的。具体实现方式仅需要提供从服务注册中心获取服务列表的API,提供给负载均衡时候的服务发现使用。

猿Why目前工作中用到的负载均衡是spring-cloud-starter-netflix-ribbon。所以,从ribbon做服务选择的时候入手,了解服务更新的原理。

服务选择入口

com.netflix.loadbalancer.RandomRule为例:

public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            // 分析服务列表更新关键入口
            List<Server> upList = lb.getReachableServers();
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }

            int index = chooseRandomInt(serverCount);
            server = upList.get(index);

            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub
		
	}
}

关键API

com.netflix.loadbalancer.BaseLoadBalancer#getReachableServers
在这里插入图片描述

如何获取最新的服务列表?

通过Debug断点,找到服务列表更新的入口。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以,调试一番,基本就能看到服务列表是如何被更新的。com.netflix.loadbalancer.ServerList#getUpdatedListOfServers方法的注释也写的很清楚。通过这个方法,可以30s更新一次服务列表。

什么时候更新服务列表?

到这里,已经知道一次的服务列表更新是如何实现的。早些时候,猜测是通过定时任务来更新的,所以看到:
org.springframework.cloud.consul.discovery.ConsulCatalogWatch源码的时候,误以为是这里进行服务列表的更新,没有继续追源码。直到今天发现:这个API并没有更新服务列表,只是在最后发布了一个事件。猿Why理解,可以借助这个事件的发布,自行扩展服务列表更新的逻辑。
在这里插入图片描述
既然不是org.springframework.cloud.consul.discovery.ConsulCatalogWatch更新服务列表,那么更新服务列表的初始化配置在哪里呢?在com.netflix.loadbalancer.ServerList#getUpdatedListOfServers打断点,看到调用栈的信息后发现:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样,就明白服务列表更新,是由一个scheduler来做的,默认周期是30s一次。

服务列表更新算法是否支持扩展?

如果支持扩展,入口应当是在这里。留下疑问,给后续补充
在这里插入图片描述

扩展性补充

负载均衡使用的客户端Bean自定义即可扩展,从以下的属性类中可以看出,当前支持哪些属性的自定义扩展
在这里插入图片描述

服务列表更新规则扩展

在这里插入图片描述

负载均衡扩展

在这里插入图片描述
有趣的事情是:可以看到负载均衡客户端Bean的初始化是在Bean被调用的时候实例化的。所以大胆猜想:@ConditionalOnMissingBean的应用有两个意义:①当指定类型的Bean不存在是后,做兜底使用;②该注解标注的Bean的实例化,会在Bean被用到的时候进行实例化。
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值