前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >性能测试 —— Dubbo 基准测试

性能测试 —— Dubbo 基准测试

作者头像
芋道源码
发布2019-08-06 14:18:20
1.9K0
发布2019-08-06 14:18:20
举报
文章被收录于专栏:芋道源码1024芋道源码1024

摘要: 原创出处 http://www.iocoder.cn/Performance-Testing/Dubbo-benchmark/ 「芋道源码」欢迎转载,保留摘要,谢谢!

  • 1. 概述
  • 2. 性能指标
  • 3. 测试工具
  • 4. dubbo-benchmark
  • 666. 彩蛋

1. 概述

在 2019.05.21 号,在经历了 1 年多的孵化,Dubbo 终于迎来了 Apache 毕业。在这期间,Dubbo 做了比较多的功能迭代,提供了 NodeJS、Python、Go 等语言的支持,也举办了多次社区活动,在网上的“骂声”也少了。

作为一个长期使用,并且坚持使用 Dubbo 的开发者,还是比较愉快的。可能,又经历了一次技术正确的选择。当然,更愉快的是,Spring Cloud Alibaba 貌似,也孵化的差不多,双剑合并,biubiubiu 。

本文,我们就来对 Dubbo 做一次性能基准测试。当写下这句话,突然想到了徐大sao:“今天天气不错,所以来吃顿好的”。

2. 性能指标

在 Dubbo 官方团队提供的 《Dubbo 性能测试报告》 的文章里,我们比较明确的可以看到希望的性能指标:

场景名称

对应指标名称

期望值范围

实际值

是否满足期望(是/否)

1k数据

响应时间

0.9ms

0.79ms

1k数据

TPS

10000

11994

3. 测试工具

目前可用于 Dubbo 测试的工具如下:

  • dubbo-benchmark :Dubbo 官方,基于 JMH 实现的 Dubbo 性能基准测试工具。 对 JMH 不了解的胖友,可以看看 forever alone 的基友写的 《JAVA 拾遗 — JMH 与 8 个测试陷阱》
  • jmeter-plugins-for-apache-dubbo :社区贡献,压力测试工具 Jmeter 对 Dubbo 的插件拓展。

考虑到测试的简便性,以及学习成本(大多数人不会使用 JMeter),所以我们采用 dubbo-benchmark ,虽然说 JMH 也好多人不会。但是,因为 dubbo-benchmark 提供了开箱即用的脚本,即使不了解 JMH ,也能很方便的快速上手。当然,还是希望胖友能去了解下 JMH ,毕竟是 Java 微基准测试框架,可以用来测试我们编写的很多代码的性能。

4. dubbo-benchmark

4.1 项目结构

在开始正式测试之前,我们先来了解下 dubbo-benchmark 项目的大体结构。

项目结构

分了比较多的 Maven 模块,我们将它们的关系,重新梳理如下图:

项目层级

第一层 benchmark-base

提供 Dubbo Service 的实现,如下图:

benchmark-base

  • UserService 类中,定义了我们业务场景中常用的四种方法: public interface UserService {public boolean existUser(String email); public boolean createUser(User user); public User getUser(long id); public Page<User> listUser(int pageNo); }
    • UserServiceImpl 的实现,胖友自己看下,比较简单。
  • AbstractClient,理论来说,应该放到 client-base 中,可能迷路了。

第二层 client-base

实现 Dubbo 消费端的,基于 JMH ,实现 Benchmark 基类。重点在 benchmark.Client 类,代码如下:

代码语言:javascript
复制
private static final int CONCURRENCY = 32;

public static void main(String[] args) throws Exception {
    Options opt;
    ChainedOptionsBuilder optBuilder = new OptionsBuilder()
            // benchmark 所在的类名,此处就是 Client
            .include(Client.class.getSimpleName())
            // 预热 3 轮,每轮 10 秒
            .warmupIterations(3)
            .warmupTime(TimeValue.seconds(10))
            // 测量(测试)3 轮,每轮 10 秒
            .measurementIterations(3)
            .measurementTime(TimeValue.seconds(10))
            // 并发线程数为 32
            .threads(CONCURRENCY)
            // 进行 fork 的次数。如果 fork 数是 2 的话,则 JMH 会 fork 出两个进程来进行测试。
            .forks(1);

    // 设置报告结果
    opt = doOptions(optBuilder).build();

    new Runner(opt).run();
}

private static ChainedOptionsBuilder doOptions(ChainedOptionsBuilder optBuilder) {
    String output = System.getProperty("benchmark.output");
    if (output != null && !output.trim().isEmpty()) {
        optBuilder.output(output);
    }
    return optBuilder;
}
  • 胖友自己看下注释。
  • 如果对 JMH 还是不了解的胖友,可以再看看如下两篇文章:
    • 《Java 微基准测试框架 JMH》
    • 《Java 并发编程笔记:JMH 性能测试框架》

在 Client 类中,定义了对 UserService 调用的四个 Benchmark 方法,代码如下:

代码语言:javascript
复制
private final ClassPathXmlApplicationContext context;
private final UserService userService;

public Client() {
    // 读取 consumer.xml 配置文件,并启动 Spring 容器。这个配置文件,由子项目配置
    context = new ClassPathXmlApplicationContext("consumer.xml");
    context.start();
    // 获得 UserService Bean
    userService = (UserService) context.getBean("userService");
}

@Override
protected UserService getUserService() {
    return userService;
}

@TearDown
public void close() throws IOException {
    ProtocolConfig.destroyAll();
    context.close();
}

@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Override
public boolean existUser() throws Exception {
    return super.existUser();
}

@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Override
public boolean createUser() throws Exception {
    return super.createUser();
}

@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Override
public User getUser() throws Exception {
    return super.getUser();
}

@Benchmark
@BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Override
public Page<User> listUser() throws Exception {
    return super.listUser();
}

第二层 server-base

实现 Dubbo 消费端的,启动 Dubbo 服务。重点在 benchmark.Server 类,代码如下:

代码语言:javascript
复制
public class Server {

    public static void main(String[] args) throws InterruptedException {
        // 读取 provider.xml 配置文件,并启动 Spring 容器。这个配置文件,由子项目配置
        try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml")) {
            context.start();
            // sleep ,防止进程结束
            Thread.sleep(Integer.MAX_VALUE);
        }
    }

}
  • 因为是被测方,所以无需集成到 JMH 中。

第三层 {protocol}-{serialize}-client

具体协议( Protocol ),使用具体序列化( Serialize ) 方式的消费者。

第四层 {protocol}-{serialize}-server

具体协议( Protocol ),使用具体序列化( Serialize ) 方式的提供者。

4.2 测试环境

  • 型号 :ecs.c5.xlarge 艿艿:和我一样抠门(穷)的胖友,可以买竞价类型服务器,使用完后,做成镜像。等下次需要使用的时候,恢复一下。HOHO 。
  • 系统 :CentOS 7.6 64位
  • CPU :4 核
  • 内存 :8 GB
  • 磁盘 :40 GB ESSD 云盘
  • Java :OpenJDK Runtime Environment (build 1.8.0_212-b04)
  • Dubbo :2.6.1 > 虽然 Dubbo 项目本身已经完成孵化,但是 dubbo-benchmark 并未更新到最新版本的 2.7.2 。所以,本文还是测试 Dubbo 2.6.1 版本。当然,这个对测试结果影响不大,妥妥的。

4.3 安装 dubbo-benchmark

第一步,克隆项目

代码语言:javascript
复制
git clone https://github.com/apache/dubbo-benchmark.git
cd dubbo-benchmark

第二步,启动服务提供者

代码语言:javascript
复制
sh benchmark.sh dubbo-kryo-server

会有一个编译的过程,耐心等待。

第三步,启动服务消费者

需要新启一个终端

代码语言:javascript
复制
sh benchmark.sh dubbo-kryo-client

开始 JMH 测试…整个测试过程,持续 15 分钟左右。

4.4 dubbo-hessianlite

本小节,我们来测试 dubbo-hessianlite-client 和 dubbo-hessianlite-server 。

这个组合,是我们使用 Dubbo 最主流的方式。

  • 协议:Dubbo
  • 序列化:hessian-lite ,Dubbo 对 Hessian 提供的序列化方式的性能优化和 Bug 修复。
  • 通信:Netty4

第一步,启动服务提供者

代码语言:javascript
复制
sh benchmark.sh dubbo-hessianlite-server

第二步,启动服务消费者

需要新启一个终端

代码语言:javascript
复制
sh benchmark.sh dubbo-hessianlite-client

? 测试结果

代码语言:javascript
复制
Benchmark                               Mode      Cnt   Score   Error   Units
Client.createUser                      thrpt        3  16.887 ? 1.729  ops/ms
Client.existUser                       thrpt        3  47.293 ? 4.993  ops/ms
Client.getUser                         thrpt        3  19.698 ? 8.588  ops/ms
Client.listUser                        thrpt        3   3.457 ? 0.180  ops/ms
Client.createUser                       avgt        3   1.416 ? 0.308   ms/op
Client.existUser                        avgt        3   0.678 ? 0.038   ms/op
Client.getUser                          avgt        3   1.657 ? 0.359   ms/op
Client.listUser                         avgt        3   9.299 ? 0.872   ms/op
Client.createUser                     sample   499898   1.918 ? 0.007   ms/op
Client.createUser:createUser?p0.00    sample            0.279           ms/op
Client.createUser:createUser?p0.50    sample            1.448           ms/op
Client.createUser:createUser?p0.90    sample            2.613           ms/op
Client.createUser:createUser?p0.95    sample            3.027           ms/op
Client.createUser:createUser?p0.99    sample            9.732           ms/op
Client.createUser:createUser?p0.999   sample           16.876           ms/op
Client.createUser:createUser?p0.9999  sample           28.280           ms/op
Client.createUser:createUser?p1.00    sample           39.453           ms/op
Client.existUser                      sample  1376160   0.697 ? 0.002   ms/op
Client.existUser:existUser?p0.00      sample            0.094           ms/op
Client.existUser:existUser?p0.50      sample            0.647           ms/op
Client.existUser:existUser?p0.90      sample            0.842           ms/op
Client.existUser:existUser?p0.95      sample            0.921           ms/op
Client.existUser:existUser?p0.99      sample            1.425           ms/op
Client.existUser:existUser?p0.999     sample           10.355           ms/op
Client.existUser:existUser?p0.9999    sample           16.145           ms/op
Client.existUser:existUser?p1.00      sample           24.773           ms/op
Client.getUser                        sample   568869   1.686 ? 0.006   ms/op
Client.getUser:getUser?p0.00          sample            0.262           ms/op
Client.getUser:getUser?p0.50          sample            1.436           ms/op
Client.getUser:getUser?p0.90          sample            1.954           ms/op
Client.getUser:getUser?p0.95          sample            2.609           ms/op
Client.getUser:getUser?p0.99          sample            9.634           ms/op
Client.getUser:getUser?p0.999         sample           15.862           ms/op
Client.getUser:getUser?p0.9999        sample           31.217           ms/op
Client.getUser:getUser?p1.00          sample           44.302           ms/op
Client.listUser                       sample   103394   9.272 ? 0.038   ms/op
Client.listUser:listUser?p0.00        sample            1.792           ms/op
Client.listUser:listUser?p0.50        sample            9.060           ms/op
Client.listUser:listUser?p0.90        sample           14.287           ms/op
Client.listUser:listUser?p0.95        sample           15.679           ms/op
Client.listUser:listUser?p0.99        sample           17.336           ms/op
Client.listUser:listUser?p0.999       sample           30.966           ms/op
Client.listUser:listUser?p0.9999      sample           38.161           ms/op
Client.listUser:listUser?p1.00        sample           45.351           ms/op

4.5 dubbo-fst

本小节,我们来测试 dubbo-fst-client 和 dubbo-fst-server 。

这个组合,是我们使用 Dubbo 最主流的方式。

  • 协议:Dubbo
  • 序列化:FST
  • 通信:Netty4

第一步,启动服务提供者

代码语言:javascript
复制
sh benchmark.sh dubbo-fst-server

第二步,启动服务消费者

需要新启一个终端

代码语言:javascript
复制
sh benchmark.sh dubbo-fst-client

? 测试结果

代码语言:javascript
复制
Benchmark                               Mode      Cnt   Score    Error   Units
Client.createUser                      thrpt        3  44.810 ?  5.152  ops/ms
Client.existUser                       thrpt        3  53.153 ? 49.787  ops/ms
Client.getUser                         thrpt        3  41.754 ?  8.210  ops/ms
Client.listUser                        thrpt        3  14.791 ?  3.458  ops/ms
Client.createUser                       avgt        3   0.719 ?  0.080   ms/op
Client.existUser                        avgt        3   0.574 ?  0.434   ms/op
Client.getUser                          avgt        3   0.703 ?  0.045   ms/op
Client.listUser                         avgt        3   2.189 ?  0.353   ms/op
Client.createUser                     sample  1267915   0.756 ?  0.002   ms/op
Client.createUser:createUser?p0.00    sample            0.099            ms/op
Client.createUser:createUser?p0.50    sample            0.678            ms/op
Client.createUser:createUser?p0.90    sample            0.888            ms/op
Client.createUser:createUser?p0.95    sample            1.034            ms/op
Client.createUser:createUser?p0.99    sample            3.383            ms/op
Client.createUser:createUser?p0.999   sample           10.502            ms/op
Client.createUser:createUser?p0.9999  sample           22.650            ms/op
Client.createUser:createUser?p1.00    sample           35.979            ms/op
Client.existUser                      sample  1461428   0.656 ?  0.002   ms/op
Client.existUser:existUser?p0.00      sample            0.077            ms/op
Client.existUser:existUser?p0.50      sample            0.504            ms/op
Client.existUser:existUser?p0.90      sample            1.128            ms/op
Client.existUser:existUser?p0.95      sample            1.516            ms/op
Client.existUser:existUser?p0.99      sample            2.802            ms/op
Client.existUser:existUser?p0.999     sample            6.452            ms/op
Client.existUser:existUser?p0.9999    sample           33.358            ms/op
Client.existUser:existUser?p1.00      sample           58.262            ms/op
Client.getUser                        sample  1270938   0.755 ?  0.003   ms/op
Client.getUser:getUser?p0.00          sample            0.084            ms/op
Client.getUser:getUser?p0.50          sample            0.588            ms/op
Client.getUser:getUser?p0.90          sample            1.034            ms/op
Client.getUser:getUser?p0.95          sample            1.626            ms/op
Client.getUser:getUser?p0.99          sample            4.473            ms/op
Client.getUser:getUser?p0.999         sample           10.830            ms/op
Client.getUser:getUser?p0.9999        sample           27.719            ms/op
Client.getUser:getUser?p1.00          sample           45.875            ms/op
Client.listUser                       sample   442763   2.166 ?  0.009   ms/op
Client.listUser:listUser?p0.00        sample            0.306            ms/op
Client.listUser:listUser?p0.50        sample            1.767            ms/op
Client.listUser:listUser?p0.90        sample            3.039            ms/op
Client.listUser:listUser?p0.95        sample            4.415            ms/op
Client.listUser:listUser?p0.99        sample           11.551            ms/op
Client.listUser:listUser?p0.999       sample           21.045            ms/op
Client.listUser:listUser?p0.9999      sample           32.702            ms/op
Client.listUser:listUser?p1.00        sample           45.089            ms/op

4.6 dubbo-kryo

本小节,我们来测试 dubbo-kryo-client 和 dubbo-kryo-server 。

  • 协议:Dubbo
  • 序列化:Kryo
  • 通信:Netty4

第一步,启动服务提供者

代码语言:javascript
复制
sh benchmark.sh dubbo-kryo-server

第二步,启动服务消费者

需要新启一个终端

代码语言:javascript
复制
sh benchmark.sh dubbo-kryo-client

? 测试结果

代码语言:javascript
复制
Benchmark                               Mode      Cnt   Score   Error   Units
Client.createUser                      thrpt        3  33.678 ? 2.656  ops/ms
Client.existUser                       thrpt        3  50.030 ? 3.509  ops/ms
Client.getUser                         thrpt        3  34.125 ? 4.886  ops/ms
Client.listUser                        thrpt        3  11.929 ? 1.746  ops/ms
Client.createUser                       avgt        3   0.955 ? 0.164   ms/op
Client.existUser                        avgt        3   0.642 ? 0.051   ms/op
Client.getUser                          avgt        3   0.940 ? 0.071   ms/op
Client.listUser                         avgt        3   2.603 ? 0.748   ms/op
Client.createUser                     sample   985106   0.973 ? 0.003   ms/op
Client.createUser:createUser?p0.00    sample            0.148           ms/op
Client.createUser:createUser?p0.50    sample            0.855           ms/op
Client.createUser:createUser?p0.90    sample            1.147           ms/op
Client.createUser:createUser?p0.95    sample            1.315           ms/op
Client.createUser:createUser?p0.99    sample            5.300           ms/op
Client.createUser:createUser?p0.999   sample           12.517           ms/op
Client.createUser:createUser?p0.9999  sample           21.037           ms/op
Client.createUser:createUser?p1.00    sample           31.850           ms/op
Client.existUser                      sample  1470527   0.652 ? 0.001   ms/op
Client.existUser:existUser?p0.00      sample            0.092           ms/op
Client.existUser:existUser?p0.50      sample            0.601           ms/op
Client.existUser:existUser?p0.90      sample            0.800           ms/op
Client.existUser:existUser?p0.95      sample            0.876           ms/op
Client.existUser:existUser?p0.99      sample            1.550           ms/op
Client.existUser:existUser?p0.999     sample            9.650           ms/op
Client.existUser:existUser?p0.9999    sample           14.844           ms/op
Client.existUser:existUser?p1.00      sample           30.573           ms/op
Client.getUser                        sample  1001893   0.957 ? 0.004   ms/op
Client.getUser:getUser?p0.00          sample            0.127           ms/op
Client.getUser:getUser?p0.50          sample            0.741           ms/op
Client.getUser:getUser?p0.90          sample            1.401           ms/op
Client.getUser:getUser?p0.95          sample            2.191           ms/op
Client.getUser:getUser?p0.99          sample            5.546           ms/op
Client.getUser:getUser?p0.999         sample           12.059           ms/op
Client.getUser:getUser?p0.9999        sample           24.518           ms/op
Client.getUser:getUser?p1.00          sample           49.873           ms/op
Client.listUser                       sample   363958   2.636 ? 0.013   ms/op
Client.listUser:listUser?p0.00        sample            0.390           ms/op
Client.listUser:listUser?p0.50        sample            2.071           ms/op
Client.listUser:listUser?p0.90        sample            4.084           ms/op
Client.listUser:listUser?p0.95        sample            6.947           ms/op
Client.listUser:listUser?p0.99        sample           12.403           ms/op
Client.listUser:listUser?p0.999       sample           22.940           ms/op
Client.listUser:listUser?p0.9999      sample           40.935           ms/op
Client.listUser:listUser?p1.00        sample           60.097           ms/op

4.7 小结

可能有胖友,对 JMH 的结果报告不熟悉,这里简单介绍下:

  • Mode :thrpt ,throughput 的缩写,吞吐量,单位为:ops/ms ,所以需要乘以 1000 ,换算成 QPS 。
  • Mode :avgt ,AverageTime 的缩写,每个操作?的时间,单位为 ms 毫秒。
  • Mode :sample ,采样分布。每一行代表,代表百分之多少(?p)的请求,在多少毫秒内。

整理结果如下表:

性能结果

  • 三个测试用例,差别是序列化使用的库,所以序列化的性能,决定了整体的性能结果。
  • 方法的性能排行是:existUser > getUser > createUser > listUser
  • 项目的性能排行是:dubbo-fst > dubbo-kryo > dubbo-hessianlite

当然,得到这样一个测试结果,我们很自然的会有一个疑惑,既然 FST 和 Kryo 性能比 Hessian Lite 好,为什么默认选择的还是 Hessian Lite 呢?因为在 RPC 场景下,我们有跨语言的诉求,而 FST 和 Kryo 是 Java 序列化的库,不支持跨语言,而 Hessian Lite 支持。

666. 彩蛋

因为 dubbo-benchmark 项目的存在,所以整个测试的过程,体验还是比较舒服,测试也是非常顺利的。当然,还是比较期待 dubbo-benchmark 后续能更新的更牛逼:

  • 例如说,支持更多的序列化方式,因为最新版本有了 Gson、Probufstuff 等新的序列化支持
  • 再例如说,支持除了 Dubbo 协议之外,Rest 等等。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 芋道源码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. 性能指标
  • 3. 测试工具
  • 4. dubbo-benchmark
    • 4.1 项目结构
      • 4.2 测试环境
        • 4.3 安装 dubbo-benchmark
          • 4.4 dubbo-hessianlite
            • 4.5 dubbo-fst
              • 4.6 dubbo-kryo
                • 4.7 小结
                • 666. 彩蛋
                相关产品与服务
                文件存储
                文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档