《高性能Redis组件》测试验证-第02节:高性能Redis组件基准性能测试
作者:冰河
星球:http://m6z.cn/6aeFbs
博客:https://binghe.site
文章汇总:https://binghe.site/md/all/all.html
源码获取地址:https://t.zsxq.com/0dhvFs5oR
沉淀,成长,突破,帮助他人,成就自我。
- 本章难度:★★☆☆☆
- 本章重点:对高性能Redis组件进行JMH基准性能测试,从总体上理解高性能Redis组件防缓存击穿、穿透和雪崩问题的核心设计思想,并从全局视角了解高性能Redis组件的设计和架构思想,并能够将其灵活应用到自身实际项目中。
大家好,我是冰河~~
完成高性能Redis组件核心功能的设计与实现,重点实现了基础功能、分布式锁以及防缓存击穿、穿透和雪崩问题的核心功能后,我们又完成了对高性能Redis组件对外提供的接口单元测试。接下来,我们再通过JMH对高性能Redis组件进行性能压力测试。
一、前言
都说高性能Redis组件的性能比较高,那如何确认其性能呢,一种很简单的方式就是对高性能Redis组件进行JMH基准性能测试,用数据说话比我们自己口头吹更有说服了。本节,就带着大家基于JMH对高性能Redis组件进行基准性能测试。
二、本节诉求
对高性能Redis组件进行JMH基准性能测试,从总体上理解高性能Redis组件防缓存击穿、穿透和雪崩问题的核心设计思想,并从全局视角了解高性能Redis组件的设计和架构思想,并能够将其灵活应用到自身实际项目中。
三、编码实现
(1)引入依赖
对代码进行基准性能测试时,需要引入JMH依赖,在pom.xml中引入如下依赖。
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
(2)实现AbstractSpringBenchmark类
AbstractSpringBenchmark类主要是JMH整合SpringBoot的抽象类。
源码详见:io.binghe.redis.plugin.test.jmh.AbstractSpringBenchmark。
@State(Scope.Benchmark)
public abstract class AbstractSpringBenchmark {
protected ConfigurableApplicationContext context;
/**
* 初始化Spring上下文(每个Benchmark级别执行一次)
*/
@Setup(Level.Trial)
public void initSpringContext() {
System.out.println("=== 初始化Spring Boot上下文 ===");
long start = System.currentTimeMillis();
// 禁用启动banner,减少日志输出
System.setProperty("spring.main.banner-mode", "off");
System.setProperty("logging.level.root", "WARN");
this.context = SpringApplication.run(SpringRedisStarter.class);
long cost = System.currentTimeMillis() - start;
System.out.println("=== Spring Boot启动完成,耗时: " + cost + "ms ===");
}
/**
* 清理Spring上下文
*/
@TearDown(Level.Trial)
public void closeSpringContext() {
if (context != null) {
context.close();
System.out.println("=== Spring Boot上下文已关闭 ===");
}
}
/**
* 获取Bean
*/
@SuppressWarnings("unchecked")
protected <T> T getBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
/**
* 获取Bean名称
*/
protected Object getBean(String beanName) {
return context.getBean(beanName);
}
}
(3)实现DistributeCacheServiceJmhTest类
DistributeCacheServiceJmhTest类是JMH基准性能测试的核心类,对高性能组件Redis组件对外提供的接口方法进行基准性能测试。
源码详见:io.binghe.redis.plugin.test.jmh.DistributeCacheServiceJmhTest。
@BenchmarkMode(Mode.All)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@Threads(8)
public class DistributeCacheServiceJmhTest extends AbstractSpringBenchmark {
private DistributeCacheService distributeCacheService;
@Setup(Level.Trial)
public void setup() {
this.distributeCacheService = getBean(DistributeCacheService.class);
}
@Benchmark
public void testQueryWithPassThrough(){
distributeCacheService.queryWithPassThrough("pass:through:", 1002852L, User.class, this::getUser, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithLogicalExpire(){
distributeCacheService.queryWithLogicalExpire("logical:expire:", 1002852L, User.class, this::getUser, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithLogicalExpireWithoutArgs(){
distributeCacheService.queryWithLogicalExpireWithoutArgs("logical:expire005:", User.class, this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithLogicalExpire(){
distributeCacheService.queryWithLogicalExpire("logical:expire2:", 100285212, Integer.class, this::getId, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithLogicalExpireWithoutArgs(){
distributeCacheService.queryWithLogicalExpireWithoutArgs("logical:expire2006:", Integer.class, this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithLogicalExpireList(){
distributeCacheService.queryWithLogicalExpireList("logical:expire:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithLogicalExpireListWithoutArgs(){
distributeCacheService.queryWithLogicalExpireListWithoutArgs("logical:expire:list007:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithLogicalExpireList(){
distributeCacheService.queryWithLogicalExpireList("logical:expire:list2:", 100285213, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithLogicalExpireListWithoutArgs(){
distributeCacheService.queryWithLogicalExpireListWithoutArgs("logical:expire:list2008:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithMutex(){
distributeCacheService.queryWithMutex("mutex:", 1002852L, User.class, this::getUser, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithMutexWithoutArgs(){
distributeCacheService.queryWithMutexWithoutArgs("mutex009:", User.class, this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithMutex(){
distributeCacheService.queryWithMutex("mutex2:", 100285214, Integer.class, this::getId, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithMutexWithoutArgs(){
distributeCacheService.queryWithMutexWithoutArgs("mutex2010:", Integer.class, this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithMutexList(){
distributeCacheService.queryWithMutexList("mutex:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQueryWithMutexListWithoutArgs(){
distributeCacheService.queryWithMutexListWithoutArgs("mutex:list011:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithMutexList(){
distributeCacheService.queryWithMutexList("mutex:list2:", 123, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
}
@Benchmark
public void testQuerySimpleDataWithMutexListWithoutArgs(){
distributeCacheService.queryWithMutexListWithoutArgs("mutex:list2012:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
}
/**
* 模拟带参数从数据库查询对象
*/
public User getUser(Long id){
return new User(id, "binghe");
}
/**
* 默认不带参数从数据库查询对象
*/
public User getUserWithoutArgs(){
return new User(1L, "binghe");
}
/**
* 模拟带参数查询从数据库对象列表
*/
public List<User> getUserList(String type){
return Arrays.asList(
new User(1L, "binghe001"),
new User(2L, "binghe002"),
new User(3L, "binghe003")
);
}
/**
* 模拟不带参数从数据库查询对象列表
*/
public List<User> getUserListWithoutArgs(){
return Arrays.asList(
new User(1L, "binghe001"),
new User(2L, "binghe002"),
new User(3L, "binghe003")
);
}
/**
* 模拟带参数从数据库查询简单数据类型数据
*/
public Integer getId(Integer id){
return id;
}
/**
* 模拟不带参数从数据库查询简单数据类型数据
*/
public Integer getIdWithoutArgs(){
return 0;
}
/**
* 模拟带参数从数据库查询简单数据类型数据列表
*/
public List<Integer> getIds(Integer id){
return Arrays.asList(0,0,0);
}
/**
* 模拟不带参数从数据库查询简单数据类型数据列表
*/
public List<Integer> getIdsWithoutArgs(){
return Arrays.asList(0,0,0);
}
public static void main(String[] args) throws RunnerException {
Options opts = new OptionsBuilder().include(DistributeCacheServiceJmhTest.class.getSimpleName()).resultFormat(ResultFormatType.JSON).build();
new Runner(opts).run();
}
}
随后,就可以运行DistributeCacheServiceJmhTest类对组件进行基准性能测试了。
注意:由于运行基准测试时,会启动过个SpringBoot进程,所以,运行基准测试之前,需要将application.yml中的server.port配置设置为0,如下所示。
server:
port: 0
另外,高性能Redis组件的核心是读写Redis,受限于访问Redis的性能,基准测试最好一次对一个方法进行测试,不宜同时对太多方法并发测试。上述代码只是给出了所有方法的基准测试。
运行基准测试后,会在项目的根目录下生成jmh-result.json文件,此时文件基准测试的结果文件。
四、
四、本节总结
本节,主要对高性能Redis组件进行了JMH基准性能测试。
最后,可以在评论区写下你学完本章节的收获,祝大家都能学有所成,我们一起搞定高性能Redis组件。
五、写在最后
在冰河的知识星球除了热更的AI大模型外,还有其他十几个项目,像实战AI大模型、手写高性能敏组件、手写线程池、手写高性能SQL引擎、手写高性能Polaris网关、手写高性能熔断组件、手写通用指标上报组件、手写高性能数据库路由组件、手写分布式IM即时通讯系统、手写Seckill分布式秒杀系统、手写高性能RPC、实战高并发设计模式、简易商城系统等等。
这些项目的需求、方案、架构、落地等均来自互联网真实业务场景,让你真正学到互联网大厂的业务与技术落地方案,并将其有效转化为自己的知识储备。
值得一提的是:冰河自研的Polaris高性能网关比某些开源网关项目性能更高,目前正在热更AI大模型项目,也正在实现MCP,实战AI大模型正在热更中,全程带你分析原理和手撸代码。
你还在等啥?不少小伙伴经过星球硬核技术和项目的历练,早已成功跳槽加薪,实现薪资翻倍,而你,还在原地踏步,抱怨大环境不好。抛弃焦虑和抱怨,我们一起塌下心来沉淀硬核技术和项目,让自己的薪资更上一层楼。

目前,领券加入星球就可以跟冰河一起学习《DeepSeek大模型》、《手写高性能脱敏组件》、《手写线程池》、《手写高性能SQL引擎》、《手写高性能Polaris网关》、《手写高性能RPC项目》、《分布式Seckill秒杀系统》、《分布式IM即时通讯系统》《手写高性能通用熔断组件项目》、《手写高性能通用监控指标上报组件》、《手写高性能数据库路由组件》、《手写简易商城脚手架项目》、《Spring6核心技术与源码解析》和《实战高并发设计模式》,从零开始介绍原理、设计架构、手撸代码。
花很少的钱就能学这么多硬核技术、中间件项目和大厂秒杀系统与分布式IM即时通讯系统,比其他培训机构不知便宜多少倍,硬核多少倍,如果是我,我会买他个十年!
加入要趁早,后续还会随着项目和加入的人数涨价,而且只会涨,不会降,先加入的小伙伴就是赚到。
另外,还有一个限时福利,邀请一个小伙伴加入,冰河就会给一笔 分享有奖 ,有些小伙伴都邀请了50+人,早就回本了!
六、其他方式加入星球
- 链接 :打开链接 http://m6z.cn/6aeFbs 加入星球。
- 回复 :在公众号 冰河技术 回复 星球 领取优惠券加入星球。
特别提醒: 苹果用户进圈或续费,请加微信 hacker_binghe 扫二维码,或者去公众号 冰河技术 回复 星球 扫二维码加入星球。
好了,今天就到这儿吧,我是冰河,我们下期见~~
