Dubbo 配置 Loadbalance 不生效?撸一把源码

  发布时间:2025-11-04 21:47:37   作者:玩站小弟   我要评论
文末本文转载自微信公众号「捉虫大师」,作者捉虫大师 。转载本文请联系捉虫大师公众号。背景很久之前我给业务方写了一个 dubbo loadbalance 的扩展(为了叙述方便,这个 loadbalanc 。

文末本文转载自微信公众号「捉虫大师」,不生把源作者捉虫大师 。效撸转载本文请联系捉虫大师公众号。不生把源

背景

很久之前我给业务方写了一个 dubbo loadbalance 的效撸扩展(为了叙述方便,这个 loadbalance 扩展就叫它 XLB 吧),不生把源这两天业务方反馈说 XLB 不生效了

我心想,效撸不可能啊,不生把源都用了大半年了~

排查

于是效撸我登上不生效的 consumer 机器进行排查,还好我留了一手,不生把源当 XLB 加载时,效撸会打印一行日志

看了下这个服务,不生把源并没有打印日志,效撸说明 XLB 并没有加载成功

于是不生把源,我就去问对应的效撸开发,有按照我的不生把源文档配置 loadbalance 吗?答复:完全按照文档配置

这下我就有点不相信了,但转念一想,配置 loadbalance 如此简单,不应该出错啊,我的文档和他的应用都在 xml 文件中配置了 consumer 的 loadbalance

<dubbo:consumer loadbalance="xlb"/> 

两组配置相同,但顺序不同,测试结果为 case 1 可以加载到 XLB,case 2 不行

于是猜测,dubbo consumer 配置以后加载的为准

撸源码

显然猜测不符合我的b2b信息网风格,下面开撸源码,不感兴趣可以划过,最下面有总结

首先搞清楚,何时会加载 loadbalance,在 AbstractClusterInvoker 的 invoke 方法中,加载了 loadbalance

@Override public Result invoke(final Invocation invocation) throws RpcException {     ...     List<Invoker<T>> invokers = list(invocation);     LoadBalance loadbalance = initLoadBalance(invokers, invocation);     RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);     return doInvoke(invocation, invokers, loadbalance); } 

加载代码如下

protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {     if (CollectionUtils.isNotEmpty(invokers)) {         return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()                 .getMethodParameter(RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE));     } else {         return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);     } } 

带缓存的加载扩展

public T getExtension(String name) {     if (StringUtils.isEmpty(name)) {         throw new IllegalArgumentException("Extension name == null");     }     if ("true".equals(name)) {         return getDefaultExtension();     }     final Holder<Object> holder = getOrCreateHolder(name);     Object instance = holder.get();     if (instance == null) {         synchronized (holder) {             instance = holder.get();             if (instance == null) {                 instance = createExtension(name);                 holder.set(instance);             }         }     }     return (T) instance; } 

可以看出

loadbalance 是发起 dubbo 调用时,且当 invokers 非空时(即 providers 非空)会被初始化,后续都从缓存中取 loadbalance 是根据第一个 invoker 的 loadbalance 参数决定使用哪个 loadbalance 的

于是问题转移到 invoker 的 loadbalance 从哪来?provider 不会配置 loadbalance,所以这个参数一定是从 consumer 的配置上得到的

顺藤摸瓜,在 RegistryDirectory 的 toInvokers 方法中调用了 mergeUrl,它是在注册中心通知时被调用,也就是从注册中心上拿到 provider url 时,还得 merge 一下才能用,merge 了些什么内容?

private URL mergeUrl(URL providerUrl) {     // 1. merge consumer 参数     providerUrl = ClusterUtils.mergeUrl(providerUrl, queryMap);      // 2. merge configurator 参数     providerUrl = overrideWithConfigurator(providerUrl);     ...     return providerUrl; } 

1中 merge 了queryMap 里的参数,这个queryMap 其实就是 consumer 的参数,网站模板它来自配置的 reference

再看 reference 配置,当 ReferenceConfig 初始化时

public synchronized void init() {     ...     checkAndUpdateSubConfigs();     ...     AbstractConfig.appendParameters(map, consumer);     ... } // 2 public void checkAndUpdateSubConfigs() {     ...     checkDefault();     ... } // 3 public void checkDefault() throws IllegalStateException {     if (consumer == null) {         consumer = ApplicationModel.getConfigManager()                 .getDefaultConsumer()                 .orElse(new ConsumerConfig());     } } // 4 public Optional<ConsumerConfig> getDefaultConsumer() {     List<ConsumerConfig> consumerConfigs = getDefaultConfigs(getConfigsMap(getTagName(ConsumerConfig.class)));     if (CollectionUtils.isNotEmpty(consumerConfigs)) {         return Optional.of(consumerConfigs.get(0));     }     return Optional.empty(); } 

上面调用链从 1 到 4,4 中获取了第1个 consumer,这就是我们要找的根源

总结

每配置一个 consumer ,无论是从 xml 文件,或是 spring-boot 配置,或是 api 直接创建,都会生成一个 consumerConfig 对象

当消费接口,即配置 reference 时,会将 consumer 的参数 merge 过来,如果存在多个 consumer,会挑第一个,当然我们并不知道谁先加载

当 reference 存在 consumer 的配置时,注册中心通知的 provider urls 会和 reference 的参数进行合并,合并后生成可调用的 invoker

对于 loadbalance 来说,调用时,如果 invokers 非空,则会尝试通过第一个 invoker 的 loadbalance 参数加载负载均衡算法,第一次调用进行加载,后续调用则使用缓存

  • Tag:

相关文章

  • 电脑QQ错误代码大全解析(了解电脑QQ常见错误代码,解决通信困扰)

    摘要:电脑QQ作为一款常用的即时通信软件,在日常使用中可能会遇到各种错误代码的提示,这些错误代码可能导致我们无法正常使用或者通信受阻。本文将带你逐一解析电脑QQ常见错误代码,帮助你快速解...
    2025-11-04
  • Node.js RESTful API

    Node.js RESTful API 现在介绍Node.js的RESTful API。 。。。 什么是 RE
    2025-11-04
  • MySQL系列:一句SQL,MySQL是怎么工作的?

    对于MySQL而言,其实分为客户端与服务端。服务端,就是MySQL应用,当我们使用net start mysql命令启动的服务,其实就是启动了MySQL的服务端。 客户端,负责发送请求到
    2025-11-04
  • Redis主从复制看这篇就够了

    什么是主从复制 持久化保证了即使 redis 服务重启也会丢失数据,因为 redis 服务重启后会将硬盘上持久化的数据恢复到内存中
    2025-11-04
  • Miix510拆解教程(解密Miix510,让你了解它的内部机制)

    摘要:Miix510是联想公司推出的一款2合1可变形平板电脑,备受消费者喜爱。然而,除了外观和性能之外,许多人可能对它的内部构造一无所知。本文将为您介绍Miix510的拆解过程,带您深入...
    2025-11-04
  • 从零动手写数据库系统:数据库系统的日志模块实现

    任何一个应用只要冠以”系统“二字,那么它一定离不开一个模块,那就是”日志“。既然我们要开发一个数据库系统,那么它必然要有自己的日志模块。日志通常用于记录系统的运行状态,有点类似于快照,一旦系统出现异常
    2025-11-04

最新评论