高级程序员必会-JMH基准测试示例以及SpringBoot整合JMH

想一下,你和一些高级程序员相差在哪?

redis高可用、JVM、分布式事务、集群、Linux极端故障。但这些无非就一个功能,增删改查CURD。有些人纳闷,我也会增删改查,我怎么不是高级程序员呢?我这里指的是高性能的增删改查

测试系统有多大的压强能力

测试两个Http的性能,这里就是使用基准测试

工作中不管有JMH,还有白盒黑盒以及jmeter压力测试,这些都是需要掌握的

什么是基准测试?

1.由JDK、Oracle提供的微基准测试的一套工具API

2.多用户并发测试和综合场景测试等【性能分析】提供参考依据

3.专门用于进行代码的微基准测试,比较两段代码的性能

基准测试的意义

对业务模型中的重要业务做单独的测试,获取单⽤户运⾏时的各项性能指标,为多⽤户并发 测试和综合场景测试等性能分析提供参考依据

JMH典型使用场景

  1. 已经找出了热点函数,⽽需要对热点函数进⾏进⼀步的优化时,就可以使⽤ JMH 对优化的效 果进⾏定量的分析
  2. 想定量地知道某个函数需要执⾏多⻓时间,以及执⾏时间和输⼊ n 的相关性
  3. ⼀个函数有两种不同实现(例如JSON序列化/反序列化有Jackson和Gson实现),不知道哪种 实现性能更好

例子

1.往列表里放入10万数据,查询uuid在不在这10万条数据中,用List同时访问数量很少时是可以的,但访问数量高,你list.contain性能就会达到瓶颈

2.当用户量特别大的时候,经验丰富的程序员会说尽量不要打用户日志,但如果你需要数据预测为日后功能的开发当我没说过。因为用户日志会对系统性能造成比较大的影响。但用户量少的时候随便打,用户请求什么返回什么

使用JMH

Step1:引入依赖

<dependency>
 	<groupId>org.openjdk.jmh</groupId>
 	<artifactId>jmh-core</artifactId>
 	<version>1.21</version>
 </dependency>
 <dependency>
 	<groupId>org.openjdk.jmh</groupId>
 	<artifactId>jmh-generator-annprocess</artifactId>
 	<version>1.21</version>
 	<scope>provided</scope>
 </dependency>

Step2:HelloWord基准测试

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

/**
 * JMH基准测试
 */
public class JMHHelloWord {

    public static void main(String [] args) throws RunnerException {

        //配置进行2轮热数 测试2轮 1个线程
        //预热的原因 是JVM在代码执行多次会有优化
        Options options = new OptionsBuilder().warmupIterations(2).measurementBatchSize(2)
                .forks(1).build();

        new Runner(options).run();
    }

    /**
     * HelloWord字符串拼接测试
     */
    @Benchmark
    public void testStringAdd(){

        String s = "";

        for(int i = 0;i < 10;i++){
            s +=i;
        }
    }

    @Benchmark
    public void testStringBuild(){
        StringBuilder b = new StringBuilder();
        for(int i = 0;i < 10;i++){
            b.append(i);
        }
        b.toString();
    }
}

Step3:测试结果

相信小伙伴都知道String的字符串拼接使用StringBuilder的效率会更高,所以这里以这个为例

可以看到得到结果相同,但所使用了不同代码,使用StringBuilder的效率高出一倍多

在这里插入图片描述

SpringBoot整合JMH基准测试

整合的原因:平常我们的应用都是跑在SpirngBoot这个容器上的,比如我们要跑某段代码执行sql的效率

单线程启动应用 多线程访问

简单测试一下查询语句,我的数据库只有几条数据。但我的机器配置还可以 四核八线程的

Step1:先上整合测试代码


/**
 * 整合SpringBoot基准测试
 */
@State(Scope.Thread)
public class JMHSpringBootTest {

    //指定全局变量
    private ConfigurableApplicationContext context;

    private CouponService couponService;


    public static void main(String [] args) throws RunnerException {

        //include:指定当前这个类执行options的操作 如果你有多个options不指定其它也会执行
        Options options = new OptionsBuilder().include(JMHSpringBootTest.class.getName()+".*")
                .warmupIterations(2).measurementIterations(2)
                .forks(1).build();

        new Runner(options).run();
    }

    /**
     * Setup初始化容器的时候只执行一次
     */
    @Setup(Level.Trial)//测试级别 执行一次
    public void init(){
        String args = "";
        context = SpringApplication.run(CouponAppApplication.class,args);

        couponService = context.getBean(CouponService.class);
    }

    /**
     * Benchmark执行多次,此注解代表触发我们所要进行基准测试的方法
     */
    @Benchmark
    public void test(){
        //调用接口 简单的查询列表方法
        System.out.println(couponService.listCoupon());

    }
}

Step2:上结果

大家应该知道druid吧。在运行时也可以查看sql执行性能

结果显示每秒执行三千多 这是直接访问数据库 我什么缓存都没加 这个性能是很一般的
在这里插入图片描述

查看druid

一共发送了1万2千条请求 在三秒内完成 性能有些差
在这里插入图片描述

数字化分析性执行性能

分析性能点

1.是否存在远程调用?RPC、HTTP 这些都是耗时操作 都经过网络数据传输 (Metics告警 日志分析原因)

2.大量内存处理 List.contain() ==>set.contain

3.读多写少的场景是否可以添加缓存?比如GuavaCache 或 Redis等等

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/q736317048/article/details/113728851
jmh