1、JMH简介

JMHJava Microbenchmark Harness,是Java用来做基准测试的一个工具,该工具由OpenJDK提供并维护,测试结果可信度高。

相对于 Jmeter、ab ,它通过编写代码的方式进行压测,在特定场景下会更能评估某项性能。

本次通过使用JMH来压测Dubbo的性能(官方也是使用JMH压测)

2、使用

只需要引用两个jar即可:

<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.29</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.29</version>
</dependency>

通过一系列的注解即可使用JMH。

@State

只能用在类上,有三个取值:

Scope.Thread:默认的State,每个测试线程分配一个实例;

Scope.Benchmark:所有测试线程共享一个实例,用于测试有状态实例在多线程共享下的性能;

Scope.Group:每个线程组共享一个实例;

@OutputTimeUnit

时间单位,如毫秒 TimeUnit.MILLISECONDS、秒 TimeUnit.SECONDS

@Benchmark

声明一个public方法为基准测试方法。该类下的所有被@Benchmark注解的方法都会执行。

相当于类的main方法

@BenchmarkMode

指定测试某个接口的指标,如吞吐量、平均执行时间,一般我都是选择 ALL

Mode有:

  • Throughput: 整体吞吐量,例如“1秒内可以执行多少次调用” (thrpt,参加第5点)

  • AverageTime: 调用的平均时间,例如“每次调用平均耗时xxx毫秒”。(avgt)

  • SampleTime: 随机取样,最后输出取样结果的分布,例如“99%的调用在xxx毫秒以内,99.99%的调用在xxx毫秒以内”(simple)

  • SingleShotTime: 以上模式都是默认一次 iteration 是 1s,唯有 SingleShotTime 是只运行一次。往往同时把 warmup 次数设为0,用于测试冷启动时的性能。(ss)

@BenchmarkMode({Mode.Throughput,Mode.All})
public class StressTestProvider { }

@Measurement

用于控制压测的次数

//测量2次,每次测量的持续时间为20秒
@Measurement(iterations = 2, time = 20 , timeUnit = TimeUnit.SECONDS)

@Warmup

预热,预热可以避免首次因为一些其他因素,如CPU波动、类加载耗时这些情况的影响。

@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)

参数解释同上。

@Fork

@Fork用于指定fork出多少个子进程来执行同一基准测试方法。

@Threads

@Threads注解用于指定使用多少个线程来执行基准测试方法,如果使用@Threads指定线程数为2,那么每次测量都会创建两个线程来执行基准测试方法。

3、运行

我这里的例子是压测dubbo,源码链接在文末

完整例子:

@BenchmarkMode({Mode.All})
@Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS)
//测量次数,每次测量的持续时间
@Measurement(iterations = 3, time = 10, timeUnit = TimeUnit.SECONDS)
@Threads(32)
@Fork(1)
@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.SECONDS)
@Slf4j
public class StressTestProvider { private final AnnotationConfigApplicationContext annotationConfigApplicationContext;
private final StressTestController stressTestController; public StressTestProvider() {
annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AnnotationConfig.class);
annotationConfigApplicationContext.start();
stressTestController = annotationConfigApplicationContext.getBean("stressTestController", StressTestController.class);
} @TearDown
public void close() throws IOException {
annotationConfigApplicationContext.close();
} @Benchmark
public void string1k() {
stressTestController.string1k();
} @Benchmark
public void string100k() {
stressTestController.string100k();
} public static void main(String[] args) throws RunnerException { log.info("测试开始");
Options opt = new OptionsBuilder()
.include(StressTestProvider.class.getSimpleName())
//可以通过注解注入
// .warmupIterations(3)
// .warmupTime(TimeValue.seconds(10))
//报告输出
.result("result.json")
//报告格式
.resultFormat(ResultFormatType.JSON).build();
new Runner(opt).run();
}
}

有两种运行的方式,一般采用打成jar这种。

3.1、main方法运行

如上,只需要 配置Options,运行main方法即可,注意要使用 run模式启动,不要使用debug模式启动。

否则会报错:

transport error 202: connect failed: Connection refused ERROR

3.2、打成jar运行

有时候需要放在服务器上运行,就需要打成一个jar,需要使用单独的jar打包插件:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>jmh-demo</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

如果不想要这种打包方式,打成jar的时候一定要声明main方法入口对应的类,也就是上面StressTestProvider

还有就是,因为我的是springboot项目,我测试了一下想同时打包springboot和 jmh:

但是运行 jhm-demo.jar 发现报错:not match main class,还是老老实实通过 profile 节点打包吧。

打完包后,通过以下命令即可运行:

java -jar jmh-demo.jar  -rf json -rff result.json

-rf json 是输出 json的格式

-rff /data/result.json 是输出文件位置和名称

4、结果

执行后,会生成一个汇总结果:

Result "com.dubbo.benchmark.StressTestProvider.string1k":
N = 3
mean = 0.016 ±(99.9%) 0.022 s/op Histogram, s/op:
[0.014, 0.014) = 0
[0.014, 0.015) = 0
[0.015, 0.015) = 0
[0.015, 0.015) = 1
[0.015, 0.015) = 1
[0.015, 0.016) = 0
[0.016, 0.016) = 0
[0.016, 0.016) = 0
[0.016, 0.016) = 0
[0.016, 0.017) = 0
[0.017, 0.017) = 0
[0.017, 0.017) = 0
[0.017, 0.017) = 1
[0.017, 0.018) = 0
[0.018, 0.018) = 0
[0.018, 0.018) = 0 Percentiles, s/op:
p(0.0000) = 0.015 s/op
p(50.0000) = 0.015 s/op
p(90.0000) = 0.017 s/op
p(95.0000) = 0.017 s/op
p(99.0000) = 0.017 s/op
p(99.9000) = 0.017 s/op
p(99.9900) = 0.017 s/op
p(99.9990) = 0.017 s/op
p(99.9999) = 0.017 s/op
p(100.0000) = 0.017 s/op # 第36行
# Run complete. Total time: 00:05:12 Benchmark Mode Cnt Score Error Units
StressTestProvider.string100k thrpt 3 759.794 ± 66.300 ops/s
StressTestProvider.string1k thrpt 3 6798.005 ± 6992.093 ops/s
StressTestProvider.string100k avgt 3 0.042 ± 0.002 s/op
StressTestProvider.string1k avgt 3 0.005 ± 0.012 s/op
StressTestProvider.string100k sample 22982 0.042 ± 0.001 s/op
StressTestProvider.string100k:string100k·p0.00 sample 0.017 s/op
StressTestProvider.string100k:string100k·p0.50 sample 0.041 s/op
StressTestProvider.string100k:string100k·p0.90 sample 0.048 s/op
StressTestProvider.string100k:string100k·p0.95 sample 0.050 s/op
StressTestProvider.string100k:string100k·p0.99 sample 0.058 s/op
StressTestProvider.string100k:string100k·p0.999 sample 0.075 s/op
StressTestProvider.string100k:string100k·p0.9999 sample 0.088 s/op
StressTestProvider.string100k:string100k·p1.00 sample 0.092 s/op StressTestProvider.string1k sample 186906 0.005 ± 0.001 s/op
StressTestProvider.string1k:string1k·p0.00 sample 0.001 s/op
StressTestProvider.string1k:string1k·p0.50 sample 0.005 s/op
StressTestProvider.string1k:string1k·p0.90 sample 0.007 s/op
StressTestProvider.string1k:string1k·p0.95 sample 0.008 s/op
StressTestProvider.string1k:string1k·p0.99 sample 0.011 s/op
StressTestProvider.string1k:string1k·p0.999 sample 0.030 s/op
StressTestProvider.string1k:string1k·p0.9999 sample 0.035 s/op
StressTestProvider.string1k:string1k·p1.00 sample 0.038 s/op
StressTestProvider.string100k ss 3 0.030 ± 0.181 s/op
StressTestProvider.string1k ss 3 0.016 ± 0.022 s/op Benchmark result is saved to result.json

结果分析

简单分析一下:

只需要从第36行开始看,我这里一共压测了2个方法

  • StressTestProvider.string100k
  • StressTestProvider.string1k

Mode

这一列表示测试的名称,也就是 @BenchmarkMode你选择的测试类型,源码在此:

public enum Mode {
/**
* <p>Throughput: operations per unit of time.</p>
*/
Throughput("thrpt", "Throughput, ops/time"), /**
* <p>Average time: average time per per operation.</p>
*
*/
AverageTime("avgt", "Average time, time/op"), /**
* <p>Sample time: samples the time for each operation.</p>
*
*/
SampleTime("sample", "Sampling time"), /**
* <p>Single shot time: measures the time for a single operation.</p>
*
*/
SingleShotTime("ss", "Single shot invocation time"),

thrpt:吞吐量,也可以理解为tps、ops

avgt:每次请求的平均耗时

sample:请求样本数量,这次压测一共发了多少个请求

ss:除去冷启动,一共执行了多少轮

Cnt、Score、Units

单位

Error

误差

如果你配置了输出文件,比如我上面的 resul.json ,但是你打开是看不懂的,可以借助两个网站把文件上传进行分析:

汇总:

以上对dubbo进行了分别传输1k和100k的数据压测。

provider机器:

2核4g

CentOS release 6.4 (Final)
model name : QEMU Virtual CPU version 2.5+
stepping : 3
cpu MHz : 2099.998
cache size : 4096 KB

JVM:

jdk1.8
-server -Xmx2g -Xms2g -XX:+UseG1GC

dubbo:

版本:2.7.3
序列化:hessian2
使用默认dubbo线程数

压测参数:

32并发

结果:

1k 100k
TPS 6700 760
RTT 95% 8ms 95% 50ms
AVGTime/OP 5ms 42ms
OOM

对比了 jmeter、Apache-Benmark(ab)、jmh 这三个压测工具,个人比较推荐使用jmh,原因有:

  • jmh压测简单,只需要引入依赖,声明注解
  • 准确性高,目前大多数性能压测都是使用jmh
  • 缺点就是代码入侵

灵感参考:


(八)使用 jmh 压测 Dubbo的更多相关文章

  1. Jmeter实现dubbo接口压测案例

    当前项目中重构了消息服务,需要对消息服务接口做性能压测,评估消息服务的性能情况 通过和开发对接,目前消息服务是通过dubbo接口对内提供服务,所以才有了这边文章的记录 最初的压测这个dubbo接口有三 ...

  2. JMeter分布式压测实战(2020年清明假期学习笔记)

    一.常用压力测试工具对比 简介:目前用的常用测试工具对比 1.loadrunner 性能稳定,压测结果及颗粒度大,可以自定义脚本进行压测,但是太过于重大,功能比较繁多. 2.Apache ab(单接口 ...

  3. 基于Dubbo的压测调优实例

    不久前参与开发了一个基于dubbo分布式框架的底层账单系统,并实现了其中的一部分业务接口,目前需对这些接口进行压测,以评估生产环境所能承受的最大吞吐量.笔者以其中一个查询接口为例来回顾此次压测的整体流 ...

  4. Dubbo接口压测

    在每年的双十一大促之前,除了全链路压测,还需要各个业务方对自己业务提供的核心接口进行单接口压测,以评判系统的稳定性和承压能力. 一.准备工作 环境准备:确保应用性能环境(perf)正常可用 压测接口梳 ...

  5. dubbo接口压测工具stresstester使用

    dubbo接口压测工具stresstester使用 https://blog.csdn.net/u013822349/article/details/79412719

  6. jmeter的dubbo压测,依赖jar包要放到执行机的lib/ext下

    对于jmeter的dubbo压测场景的master-slave结构: 即master的jmeter进行任务的下发和报告的生成,slave进行任务的执行 因为dubbo压测需要依赖很多三方jar包,那么 ...

  7. 消息服务dubbo接口性能压测性能优化案例

    最近项目中的消息服务做了运营商的改动,导致这个服务做了重新开发 压测脚本如下: 开启200线程压测: tps只有200-300之间,平均耗时在700ms左右 开启500线程压测 500并发压测,发现平 ...

  8. 压力测试(八)-多节点JMeter分布式压测实战

    1.Jmeter4.0分布式压测准备工作 简介:讲解Linux服务器上jmeter进行分布式压测的相关准备工作 1.压测注意事项 the firewalls on the systems are tu ...

  9. 第八篇 -- 对数据库mysql进行连接并压测

    参考链接:https://blog.csdn.net/laofashi2015/article/details/81296929 工具:mysql-8.0.12-winx64,apache-jmete ...

随机推荐

  1. QA(测试) 工作准则建议

    身为一个专业的 QA 当然需要有自己的测试原则,这些测试原则不仅可以帮助我们提高产品质量,对外还能体现出我们的专业性,从而让合作方后续还有意愿和我们合作. 1 测试前 1.1 需求评审 必须参与,有问 ...

  2. HowToDoInJava Java 教程·翻译完成

    原文:HowToDoInJava 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. ApacheCN 学习资源 目录 核心 Java 教程 什 ...

  3. AT2348 [ARC070D] HonestOrUnkind

    不妨先从无解的情况下手,不难发现当 \(A \le B\) 时是一定无解的. 因为不诚实的 \(B\) 个人可以装作是诚实的,全部说自己这一方是诚实的对方是不诚实的我们就无法判断了. 下面我们就可以在 ...

  4. Java 内置注解简单理解

    感谢原文作者:yejg1212 原文链接 https://www.cnblogs.com/yejg1212/p/3187362.html https://www.cnblogs.com/yejg121 ...

  5. Eclipse 找不到或者无法加载主类

    最近因为频繁练习JDBC更换了几次驱动jar包,然后突然发现出现了找不到或者无法加载主类的错误, 项目上出现了一个感叹号. 解决方法: 项目-右键 properties-java Build Path ...

  6. AttributeText创建多彩文字Label --- hl

    一般用富文本实现多种花样的Label文字,下图是利用UILabel分类快速创建的多彩多样lable文字,快速简单,自定义性强,更重要的是无代码污染,特别适合轻量级使用 https://github.c ...

  7. Ext原码学习之Ext.js

    1 // JavaScript Document 2 //定义全局Ext变量 3 var Ext = Ext ||{}; 4 Ext._startTime = new Date().getTime() ...

  8. RAID磁盘阵列与配置

    RAID磁盘阵列与配置 目录 RAID磁盘阵列与配置 一.RAID磁盘阵列详解 1.RAID磁盘阵列概述 2.RAID 0(条带化存储) 3.RAID 1(镜像存储) 4.RAID 5 5.RAID ...

  9. MyBatis加强(1)~缓存机制(一级缓存、二级缓存、第三方缓存技术redis、ehcache)

    一.缓存机制 使用缓存可以使应用更快地获取数据,避免频繁的数据库交互操作,尤其是在查询越多,缓存命中率越高 的情况下,缓存的作用就越明显. 1.缓存原理:Map ■ 查询时,先从缓存区查询:找到,返回 ...

  10. 当Synchronized遇到这玩意儿,有个大坑,要注意!

    你好呀,我是歪歪. 前几天在某技术平台上看到别人提的关于 Synchronized 的一个用法问题,我觉得挺有意思的,这个问题其实也是我三年前面试某公司的时候遇到的一个真题,当时不知道面试官想要考什么 ...