性能测试 —— Dubbo 基准测试

Posted 芋道源码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性能测试 —— Dubbo 基准测试相关的知识,希望对你有一定的参考价值。

做积极的人,而不是积极废人!

源码精品专栏

 


摘要: 原创出处 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 模块,我们将它们的关系,重新梳理如下图:

性能测试 —— Dubbo 基准测试
项目层级

第一层 benchmark-base

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

性能测试 —— Dubbo 基准测试
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 类,代码如下:

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 方法,代码如下:

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 类,代码如下:

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

第一步,克隆项目

git clone https://github.com/apache/dubbo-benchmark.git
cd dubbo-benchmark

第二步,启动服务提供者

sh benchmark.sh dubbo-kryo-server

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

第三步,启动服务消费者

需要新启一个终端

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

第一步,启动服务提供者

sh benchmark.sh dubbo-hessianlite-server

第二步,启动服务消费者

需要新启一个终端

sh benchmark.sh dubbo-hessianlite-client

以上是关于性能测试 —— Dubbo 基准测试的主要内容,如果未能解决你的问题,请参考以下文章

go语言学习笔记 — 基础 — go工具(5.2): 基准测试 (性能测试)—— 获得代码内存占用和运行效率的性能数据

Go语言之基准测试

JMH的详细使用,以及压测dubbo

JMH的详细使用,以及压测dubbo

JMH的详细使用,以及压测dubbo

JMH的详细使用,以及压测dubbo