想一下,你和一些高级程序员相差在哪?
redis高可用、JVM、分布式事务、集群、Linux极端故障。但这些无非就一个功能,增删改查CURD。有些人纳闷,我也会增删改查,我怎么不是高级程序员呢?我这里指的是高性能的增删改查
测试系统有多大的压强能力
测试两个Http的性能,这里就是使用基准测试
工作中不管有JMH,还有白盒黑盒以及jmeter压力测试,这些都是需要掌握的
什么是基准测试?
1.由JDK、Oracle提供的微基准测试的一套工具API
2.多用户并发测试和综合场景测试等【性能分析】提供参考依据
3.专门用于进行代码的微基准测试,比较两段代码的性能
基准测试的意义
对业务模型中的重要业务做单独的测试,获取单⽤户运⾏时的各项性能指标,为多⽤户并发 测试和综合场景测试等性能分析提供参考依据
JMH典型使用场景
- 已经找出了热点函数,⽽需要对热点函数进⾏进⼀步的优化时,就可以使⽤ JMH 对优化的效 果进⾏定量的分析
- 想定量地知道某个函数需要执⾏多⻓时间,以及执⾏时间和输⼊ n 的相关性
- ⼀个函数有两种不同实现(例如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等等