dubbo消费端group=*时为何总发到一个group,甚至一个provider上

某项目中遇到一个问题:dubbo交易总是发到同一个provider上。
排查中发现dubbo一些比较隐蔽的机制,以此博客记录。

问题复现

经过反复尝试,控制单变量比较,找到可以稳定复现问题的关键点:

  1. 多个providergroup有相同值
  2. consumergroup=*且不设置merger

如此即可复现问题:总是发到同一个provider上。

问题定位

debug跟踪代码,发现“总发到同一个”是如何出现的,见com.alibaba.dubbo.rpc.cluster.support.MergeableClusterInvokerinvoke方法,有如下片段:

for (final Invoker invoker : invokers) {
    if (invoker.isAvailable()) {
        return invoker.invoke(invocation);
    }
}

意即,遍历List> invokers,找到第一个可用的就调用。

一个对比试验,暴露一些dubbo底层机制

在“问题复现”的关键点1中,笔者提到“多个providergroup有相同值”,即:有group,且为同一个group。如果有多个group,则不能复现问题。
例如,2个provider设置group="group1",2个provider设置group="group2",就不会有“总发到同一个”的问题,而是总发到同一个group
回头看初始化代码,发现:

  1. 如果group仅有一个,那么List> invokers中元素类型为RegistryDirectory$InvokerDelegate,即直接到provider;
  2. 当有多个group,元素类型为MockClusterInvoker,即会经过LB

详见com.alibaba.dubbo.registry.integration.RegistryDirectorytoMergeMethodInvokerMap方法,有如下片段:

if (groupMap.size() == 1) {
    result.put(method, groupMap.values().iterator().next());
} else if (groupMap.size() > 1) {
    List> groupInvokers = new ArrayList>();
    for (List> groupList : groupMap.values()) {
        groupInvokers.add(cluster.join(new StaticDirectory(groupList)));
    }
    result.put(method, groupInvokers);
}

结论

明确这个问题实际上是两部分造成:

  1. group=*merger不设置,则会用第一个可用的Invoker
  2. group仅有1个,则List元素为各provider;若group有多个,则元素为同groupprovider包装起来的一个

这样就解释解释了问题:

  1. 为何总发到一个provider上
  2. 为何总发到一个group上

你可能感兴趣的:(dubbo消费端group=*时为何总发到一个group,甚至一个provider上)