JMH 基准测试

参考文档:

https://www.cnblogs.com/kiwifly/p/11477153.html

https://www.dubby.cn/detail.html?id=9108

https://blog.csdn.net/xiang__liu/article/details/82228306

一、什么是基准测试

参考文档:

https://www.cnblogs.com/imyalost/p/5653342.html

https://www.cnblogs.com/imyalost/p/9630843.html

基准测试是一种性能测试。

通过设计合理的测试方法,选用合适的测试工具和被测系统,实现对某个特定目标场景的某项性能指标进行定量的和可对比的测试。

特质:

  • 可重复

可进行重复性的测试,这样做有利于比较每次的测试结果,得到性能结果的长期变化趋势,为系统调优和上线前的容量规划做参考。

  • 可观测

通过全方位的监控(包括测试开始到结束,执行机、服务器、数据库),及时了解和分析测试过程发生了什么。

  • 可展示

相关人员可以直观明了的了解测试结果(web界面、仪表盘、折线图树状图等形式)。

  • 真实

测试的结果反映了客户体验到的真实的情况(真实准确的业务场景+与生产一致的配置+合理正确的测试方法)。

  • 可执行

相关人员可以快速的进行测试验证修改调优(可定位可分析)。

二、JMH (Java Microbenchmark Harness)

2.1 POM

jdk9自带,低于jdk9需引入。

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.23</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.23</version>
    <scope>provided</scope>
</dependency>

2.2 demo

参考文档:

https://gist.github.com/msievers/ce80d343fc15c44bea6cbb741dde7e45

https://chendayu.com/nonsence/jmh-spring-boot/

https://yangbingdong.com/2018/spring-boot-learning-testing/

2.2.1 代码

非最佳实现,仅供参考。

@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
public class SimpleBenchmark {
    private ConfigurableApplicationContext context;
    private SimpleBean simpleBean;
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(SimpleBenchmark.class.getSimpleName())
                .build();
        new Runner(opt).run();
    }
    @Setup
    public void initDemo() {
        if (context == null) {
            context = SpringApplication.run(JmhApplication.class);
        }
        if (simpleBean == null) {
            simpleBean = context.getBean(SimpleBean.class);
        }
    }
    @TearDown
    public void closeContext() {
        if (context != null) {
            context.close();
        }
    }
    @Benchmark
    @Fork(0)
    @Threads(10)
    @Warmup(iterations = 5)
    @Measurement(iterations = 10)
    public String testIndex() throws ParamException {
        // mock
        return simpleBean.hello();
    }
}

A.基本概念

@State(Scope.Benchmark)

当存在类属性时需指定@State,如demo中指benchmark共享context,否则每次都会创建ApplicationContext。

@Benchmark

相当于Junit中的@Test。

@Warmup(iterations = 5)

预热5轮。

@Measurement(iterations = 10)

度量10轮。

@Fork

含义是为每个benchmark创建几个独立进程,默认是1。

此处如果不设置为0则无法正常启动,应该跟springboot有关【TODO】。

@Threads

每个fork进程使用多少条线程去执行你的测试方法,默认值是Runtime.getRuntime().availableProcessors()。

@Setup 和 @TearDown

在执行 benchmark 之前/之后被执行。

@BenchmarkMode(Mode.Throughput)

Mode有多种选项,可同时支持。Throughput代表整体吞吐量,例如“1秒内可以执行多少次调用”。

B.bean

使用@Autowired或@Resource均无法注入。

2.2.2 实战

基于以上demo,对富文本搜索的如下两种实现方式进行了简单对比。

  • jpa, SQL LIKE '%text%'
  • hibernate-search

A. jpa

Benchmark                      Mode  Cnt     Score   Error  Units
SearchQueryBenchmark.testSql  thrpt   10  1768.603 ± 7.480  ops/s

B.hibernate-search

Benchmark                        Mode  Cnt     Score    Error  Units
SearchIndexBenchmark.testIndex  thrpt   10  1564.827 ± 49.493  ops/s

C.小结

hibernate-search略差于SQL LIKE

以上对比仅供参考,因为测试切入点过小:

1.数据量小,富文本文档数包含已删除在内仅415篇,每篇文档内容并不长。

2.搜索文本固定,长度固定,内容固定。

三、知识库基准测试

补充文档数至2414.

3.1hibernate-search

Benchmark                        Mode  Cnt     Score   Error  Units
SearchIndexBenchmark.testIndex  thrpt   10  1251.540 ± 8.028  ops/s

3.2jpa

Benchmark                      Mode  Cnt     Score   Error  Units
SearchQueryBenchmark.testSql  thrpt   10  1429.534 ± 8.013  ops/s

jpa还是比hibernate-search高200,这样感觉都不用上索引了。

去掉hibernate-search的分词设置。

1.jpa

Benchmark                      Mode  Cnt     Score    Error  Units
SearchQueryBenchmark.testSql  thrpt   10  1539.728 ± 35.181  ops/s

2.hibernate-search

Benchmark                        Mode  Cnt     Score     Error  Units
SearchIndexBenchmark.testIndex  thrpt   10  1638.074 ± 111.799  ops/s

数据量还原至440

1.jpa

Benchmark                      Mode  Cnt     Score    Error  Units
SearchQueryBenchmark.testSql  thrpt   10  2656.599 ± 47.034  ops/s

2.hibernate-search

Benchmark                        Mode  Cnt     Score    Error  Units
SearchIndexBenchmark.testIndex  thrpt   10  1986.480 ± 29.448  ops/s

创建索引时过滤掉已删除数据,结果差别不大

Benchmark                        Mode  Cnt     Score    Error  Units
SearchIndexBenchmark.testIndex  thrpt   10  1901.504 ± 39.296  ops/s