# 《高性能Redis组件》测试验证-第02节:高性能Redis组件基准性能测试

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)
源码获取地址:https://t.zsxq.com/0dhvFs5oR (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

  • 本章难度:★★☆☆☆
  • 本章重点:对高性能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>
1
2
3
4
5
6
7
8
9
10
11
12

(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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

(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();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

随后,就可以运行DistributeCacheServiceJmhTest类对组件进行基准性能测试了。

注意:由于运行基准测试时,会启动过个SpringBoot进程,所以,运行基准测试之前,需要将application.yml中的server.port配置设置为0,如下所示。

server:
  port: 0
1
2

另外,高性能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 扫二维码,或者去公众号 冰河技术 回复 星球 扫二维码加入星球。

好了,今天就到这儿吧,我是冰河,我们下期见~~