Dubbo: 2.7.4.1 泛化调用性能弱于2.6.2

Created on 18 Nov 2019  ·  3Comments  ·  Source: apache/dubbo

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.
  • [x] I have checked the FAQ of this repository and believe that this is not a duplicate.

Environment

  • Dubbo version: 2.7.4.1
  • Operating System version: centos 6.8
  • Java version: 1.8

Steps to reproduce this issue

使用dubbo 2.7.4.1进行dubbo泛化同步调用,相比使用dubbo 2.6.2进行dubbo泛化同步调用,2.7.4.1的QPS大概是2.6.2的60%,配置相同,只是高版本某些命名空间不同,是还有什么配置吗?

public class DubboProxyService {


    private final Map<String, ApplicationConfig> APPLICATION_CONFIG_MAP = new ConcurrentHashMap<>();

    private final Map<String, List<RegistryConfig>> REGISTRY_CONFIG_MAP = new ConcurrentHashMap<>();

    private final List<String> DUBBO_LOADBALANCE_LIST = new ArrayList<String>() {{
        // com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
        add("random");

        // com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
        add("roundrobin");

        // com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
        add("leastactive");

        // com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
        add("consistenthash");
    }};

    private final Splitter DUBBO_REGISTRIES_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();

    public Object genericInvoker(final Map<String, Object> paramMap, final DubboSelectorHandle dubboSelectorHandle, final DubboRuleHandler dubboRuleHandler) {

        ReferenceConfig<GenericService> reference = buildReferenceConfig(dubboSelectorHandle, dubboRuleHandler, paramMap.get(Constants.DUBBO_INTERFACE_NAME).toString());

        ReferenceConfigCache configCache = ReferenceConfigCache.getCache();

        GenericService genericService;
        try {
            genericService = configCache.get(reference);

            if (Objects.isNull(genericService)) {
                configCache.destroy(reference);

                throw new RuntimeException("dubbo genericService has exception");
            }
        } catch (NullPointerException e) {

            configCache.destroy(reference);

            log.error("DubboProxyService genericInvoker configCache fail, paramMap={}, cause={}", paramMap, Throwables.getStackTraceAsString(e));

            throw new RuntimeException(e.getMessage());
        }

        Pair<String[], Object[]> pair = buildParameter(paramMap);

        try {

            //log.info(JsonUtils.toJson(paramMap));
            return genericService.$invoke(paramMap.get(Constants.DUBBO_METHOD).toString(), pair.getLeft(), pair.getRight());
        } catch (GenericException e) {
            log.error("DubboProxyService genericInvoker $invoke fail, paramMap={}, cause={}", paramMap, Throwables.getStackTraceAsString(e));

            throw new RuntimeException(e.getMessage());
        }
    }

    private ReferenceConfig<GenericService> buildReferenceConfig(DubboSelectorHandle selectorHandle, DubboRuleHandler ruleHandler, String interfaceName) {

        String appName = selectorHandle.getAppName();

        ReferenceConfig<GenericService> reference = new ReferenceConfig<>();

        reference.setGeneric(true);
        reference.setApplication(APPLICATION_CONFIG_MAP.computeIfAbsent(appName, f -> new ApplicationConfig(appName)));
        reference.setRegistries(REGISTRY_CONFIG_MAP.computeIfAbsent(appName,
                f -> StreamSupport.stream(Optional.of(selectorHandle.getRegistry())
                                                  .map(DUBBO_REGISTRIES_SPLITTER::split)
                                                  .get().spliterator(), false)
                                  .map(s -> "zookeeper://" + s)
                                  .map(RegistryConfig::new)
                                  .collect(Collectors.toList())));
        reference.setInterface(interfaceName);

        Optional.ofNullable(ruleHandler).map(DubboRuleHandler::getTimeout).ifPresent(reference::setTimeout);
        Optional.ofNullable(ruleHandler).map(DubboRuleHandler::getRetries).ifPresent(reference::setRetries);

        Optional.of(selectorHandle).map(DubboSelectorHandle::getProtocol).ifPresent(s -> {
            if (!Strings.isNullOrEmpty(s)) {
                reference.setProtocol(s);
            }
        });
        Optional.ofNullable(ruleHandler).map(DubboRuleHandler::getVersion).ifPresent(s -> {
            if (!Strings.isNullOrEmpty(s)) {
                reference.setVersion(s);
            }
        });
        Optional.ofNullable(ruleHandler).map(DubboRuleHandler::getGroup).ifPresent(s -> {
            if (!Strings.isNullOrEmpty(s)) {
                reference.setGroup(s);
            }
        });
        Optional.ofNullable(ruleHandler).map(DubboRuleHandler::getLoadBalance).ifPresent(s -> {
            if (DUBBO_LOADBALANCE_LIST.contains(s)) {
                reference.setLoadbalance(s);
            }
        });

        //reference.setCluster("issFailover");

        reference.setClient("netty4");

        return reference;
    }

    private Pair<String[], Object[]> buildParameter(Map<String, Object> paramMap) {

        List<String> parameterTypes = new ArrayList<>();
        List<Object> args = new ArrayList<>();

        if (paramMap.containsKey(Constants.DUBBO_PARAM_CLASS)) {

            List<String> clazz = GsonUtils.getInstance().fromList(paramMap.get(Constants.DUBBO_PARAM_CLASS).toString(), String.class);

            AtomicBoolean hasList = new AtomicBoolean(false);
            clazz.forEach(c -> {
                parameterTypes.add(c);
                if (List.class.getName().equals(c)) {
                    hasList.set(true);
                }
            });

            if (hasList.get()) {
                String classParams = paramMap.get(Constants.DUBBO_CLASS_PARAMS).toString();

                List<Map> params = GsonUtils.getInstance().toListMap(classParams);
                args.add(params);
            } else {

                String classParams = paramMap.get(Constants.DUBBO_CLASS_PARAMS).toString();
                args.addAll(GsonUtils.getInstance().fromJson(classParams, List.class));
            }
        }

        if (paramMap.containsKey(Constants.DUBBO_GENERIC_PARAMS) && !"null".equals(paramMap.get(Constants.DUBBO_GENERIC_PARAMS).toString())) {

            Map<String, Object> map = GsonUtils.getInstance().toObjectMap(paramMap.get(Constants.DUBBO_GENERIC_PARAMS).toString());

            map.forEach((k, v) -> {

                if (v instanceof JsonArray) {
                    List<String> arg = GsonUtils.getInstance().fromList(v.toString(), String.class);

                    arg.forEach(a -> {
                        parameterTypes.add(k);
                        args.add(a);
                    });

                } else {
                    parameterTypes.add(k);
                    args.add(v);
                }
            });

        }

        return Pair.of(parameterTypes.toArray(new String[0]), args.toArray());
    }

}

Expected Result

dubbo 2.7.4.1进行泛化同步调用时,性能不弱于2.6.2

Actual Result

dubbo 2.7.4.1 进行泛化同步调用时,性能大副弱于2.6.2

If there is an exception, please attach the exception trace:

Just put your stack trace here!

Most helpful comment

2.7.5 is expected to have significant performance improve and will be released soon.

All 3 comments

2.7.5 is expected to have significant performance improve and will be released soon.

Do we have the plan when 2.7.5 will release?

最近也碰到这个问题,最近内部API网关升级dubbo到2.7.4.1,cpu使用占比很高,分享下排查总结。
(1)2.7.4.1版本的ReferenceConfig.get方法,会调用checkAndUpdateSubConfigs方法,代码:https://github.com/apache/dubbo/blob/dubbo-2.7.4.1/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
(2)2.7.6版本,ReferenceConfig.get方法不再调用checkAndUpdateSubConfigs,放到init方法执行,内部应该是优化调整元数据的更新&校验逻辑。

升级到2.7.6版本后,问题解决

附:
dubbo2.6.6:
image
dubbo2.7.4.1:
image
dubbo2.7.6:
image

Was this page helpful?
0 / 5 - 0 ratings