Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

插件是否存在性能问题? #109

Closed
roverbeta opened this issue May 22, 2020 · 8 comments
Closed

插件是否存在性能问题? #109

roverbeta opened this issue May 22, 2020 · 8 comments
Labels
FAQ FAQ

Comments

@roverbeta
Copy link

roverbeta commented May 22, 2020

插件版本:2.7.4

场景1:使用插件压测和实现JavaSamplerClient压测数据对比,压测相同接口(一个简单的say hi接口),实现JavaSamplerClient的压测方式qps能达1w,使用插件压测qps最高只有1500。

场景2:在不改变插件其他逻辑的情况下,注释掉io.github.ningyu.jmeter.plugin.dubbo.sample.DubboSample#callDubbo方法中的genericService.$invoke(methodName, parameterTypes, parameterValues);,并将res.sampleStart();提到该方法的首行。压测结果为
image

@roverbeta
Copy link
Author

初步猜测是org.apache.dubbo.config.ReferenceConfig#get中,每次都会调用org.apache.dubbo.config.ReferenceConfig#checkAndUpdateSubConfigs引起的。我尝试压测了一下checkAndUpdateSubConfigs,平均时延有14ms,对dubbo不怎么熟悉不确定这个方法做了什么,是否有必须每次都调用该方法。
image

@roverbeta
Copy link
Author

roverbeta commented May 22, 2020

测试发现通过缓存GenericService能明显提高性能

相关改动为

    private Object callDubbo(SampleResult res) {

            ...

            GenericService genericService = getGenericService(reference);
            // The registry's address is to generate the ReferenceConfigCache key
            // ReferenceConfigCache cache = ReferenceConfigCache.getCache(Constants.getAddress(this), new ReferenceConfigCache.KeyGenerator() {
            //     @Override
            //     public String generateKey(org.apache.dubbo.config.ReferenceConfig<?> referenceConfig) {
            //         return referenceConfig.toString();
            //     }
			// });
            // GenericService genericService = (GenericService) cache.get(reference);

           ...

    }
    private GenericService getGenericService(ReferenceConfig reference){
        ConcurrentHashMap<String, GenericService> genericServiceCache = getGenericServiceCache();
        String referenceKey = reference.toString();
        GenericService genericService = genericServiceCache.get(referenceKey);
        if (genericService != null){
            return genericService;
        }
        genericServiceCache.putIfAbsent(referenceKey, (GenericService) reference.get());
        return genericServiceCache.get(referenceKey);
    }
    private ConcurrentHashMap<String, GenericService> getGenericServiceCache() {
        String address = Constants.getAddress(this);
        ConcurrentHashMap<String, GenericService> genericServiceCache = GENERIC_SERVICE_CACHE.get(address);
        if (genericServiceCache != null){
            return genericServiceCache;
        }
        GENERIC_SERVICE_CACHE.putIfAbsent(address, new ConcurrentHashMap<>());
        return GENERIC_SERVICE_CACHE.get(address);
    }

修改后压测"say hi"接口结果为
image

另外可能的优化方案:
升级dubbo版本为2.7.7,并作相应的兼容。
理由是,dubbo-2.7.7 中已将org.apache.dubbo.config.ReferenceConfig#checkAndUpdateSubConfigsorg.apache.dubbo.config.ReferenceConfig#get中去除,并放到了org.apache.dubbo.config.ReferenceConfig#init

@ningyu1
Copy link
Collaborator

ningyu1 commented May 25, 2020

@roverbeta
没看明白你的意思
注释掉:genericService.$invoke(methodName, parameterTypes, parameterValues) 那你实际调用了个啥?

还有你的意思是:ReferenceConfigCache.getCache 这个ReferenceConfig缓存没有效果? 实际这个cache和你实现的map cache实际上是差不多的

@ningyu1 ningyu1 added the FAQ FAQ label May 25, 2020
@roverbeta
Copy link
Author

@ningyu1
1 注释掉:genericService.$invoke(methodName, parameterTypes, parameterValues),目的是测试在没任何调用的情况下,插件的性能,即实际没调用任何dubbo接口
2 ReferenceConfigCache是有效果的,但它只缓存了ReferenceConfig。目前插件所用版本的dubbo,会通过ReferenceConfig.get()获取代理实例,这个方法会影响性能

@ningyu1
Copy link
Collaborator

ningyu1 commented May 26, 2020

@roverbeta

  1. 没有任何调用的测试没有意义
  2. ReferenceConfigCache就是缓存ReferenceConfig对象,ReferenceConfig.get()本身也是有判断ref==null,当ref有值是直接返回的,不管执行多少次sample,只要address不变就会使用相同ReferenceConfig实例,因此ReferenceConfig.get是直接使用已初始化的ref。
  3. 插件使用泛化调用,不知道跟JavaSamplerClient中dubbo的调用方式是否相同?
  4. 建议在跑之前先预热一下,再对比看是否有差异?

@roverbeta
Copy link
Author

@ningyu1
1 sample目的是统计SampleResult.sampleStart()和SampleResult.sampleEnd()之间的代码执行的效率,跟是否有调用无关,注释掉调用,可以理解为统计的是获取ref的性能
2 是的,确实是使用的相同的实例,并且也只会初始化一次,不过我上面有提到影响性能的地方主要是get()中调用的checkAndUpdateSubConfigs(),这个方法在dubbo-2.7.7中已被移进init()中,建议先看完上面的评论哈。
3 一致的,JavaSamplerClient也是用的泛化调用
4 有经过多次测试对比,差异是比较大的,理解这里是否预热可能影响不大。
5 目前将插件的dubbo版本升级后,性能明显改善,

@ningyu1
Copy link
Collaborator

ningyu1 commented May 27, 2020

dubbo-jmeter-2.7.4
dubbo-jmeter-2 7 4

dubbo-jmeter-2.7.7
dubbo-jmeter-2 7 7

dubbo-2.7.4和2.7.7性能差别蛮大的

@RobertLiu0905
Copy link

checkAndUpdateSubConfigs()

是的,我用2.7.4和2.7.7两个版本的插件测试之后发现性能影响确实在这个方法,新版本官方把这个方法挪到其他地方了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FAQ FAQ
Projects
None yet
Development

No branches or pull requests

3 participants