用JMeter对使用Guava-BloomFilter的简易项目的性能测试(带github代码)
Jmeter查看QPS和响应时间随着时间的变化曲线(转载)
A component required a bean of type ‘redis. clients. jedis. JedisPool’ that could not be found.
SpringBoot高级篇Redis之Jedis配置
Guava教程-BloomFilter
…
0. github测试代码demo项目
先贴上对应的github项目链接(项目很粗糙)。
这个项目里包括
- docker-compose文件
- JMeter的测试项目jmx文件
- MySQL的sql文件
- 以及Java代码
1. 前言
这里不对Guava进行介绍了,完全不了解的可以网上查查相关的内容。Guava粗糙的理解就是bit版本的hashmap,但仅用于判断XX数据是否存在,并不能用于读取实际对应的数据。
这篇文章主要是自己正好想试试BloomFilter,姑且做下超粗略的测试,记录一下过程。
2. 测试环境
操作系统:MacOS 10.50.7
CPU:2.4GHZ 8核-i9
内存:32GB 2667MHz DDR4
测试工具:JMeter 5.3
数据库:MySQL 8.0.19、Redis 6.0.8
SpringBoot 2.3.4.RELEASE
3. 项目测试大致介绍
-
MySQL简单的一张表,仅含有id和name字段的myuser表,100W条记录的SQL文件,但是不想压榨自己的电脑,实际只用了约1W条数据。(毕竟代码也就测试代码,没有考虑各种高并发优化等策略)
-
比较三种情况的耗时
- 120s内1W线程,初次查询,Redis无缓存
- 120s内1W线程,Redis已有缓存(将近一般数据命中缓存的情况)
- 120s内1W线程,Reids有缓存(近一半),且配有BloomFilter
-
JMeter设置
4. 部分代码
(1)BloomFilter代码
这里让BloomFilter记住数据库的那100W条模拟数据
@Configuration
public class BloomFilterConfig {
@Bean
public BloomFilter<String> bloomFilter(){
BloomFilter<String> bloomFilter = BloomFilter.create(new Funnel<String>() {
@Override
public void funnel(String from, PrimitiveSink into) {
into.putString(from, Charsets.UTF_8);
}
},100_0000,0.01);
// 初始化bloom-fliter。
for(int i = 1;i<=100_0000;++i){
bloomFilter.put("name_"+i);
}
return bloomFilter;
}
}
(2)测试用的Controller方法
第一个,即localhost:8089/api/test/name01
的方法,只有Redis和MySQL;
第二个,即localhost:8089/api/test/name02
的方法,在第一个之前新增BloomFilter事先判断数据是否存在;
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController extends ApiController {
/**
* 服务对象
*/
@Resource
private MyuserDao myuserDao;
@Resource
private RedisUtil redisUtil;
@Resource
private BloomFilter bloomFilter;
/**
* 通过名称name查询单条数据
*
* 没有bloom-fliter,无对应数据时,Redis无->MySQL无
*
* @param name 名称
* @return 单条数据
*/
@Transactional(propagation = Propagation.SUPPORTS)
@GetMapping("/name01")
public R selectOneV1(@RequestParam("name") String name) {
// (1) Redis尝试获取数据
String json = redisUtil.getVal(name);
if (json != null) {
return success(new Gson().fromJson(json, Myuser.class));
} else {
// (2) Redis无数据,从MySQL获取数据,若存在数据则缓存到Redis
Myuser myuser = myuserDao.getUserByName(name);
if (myuser != null) {
json = new Gson().toJson(myuser);
redisUtil.setVal(name, json);
}
return success(myuser);
}
}
/**
* 通过名称name查询单条数据
*
* 有bloom-fliter,无对应数据时,直接返回null
*
* @param name 名称
* @return 单条数据
*/
@Transactional(propagation = Propagation.SUPPORTS)
@GetMapping("/name02")
public R selectOneV2(@RequestParam("name") String name) {
// (0) 先bloom-filter判断是否存在对应的数据,存在则继续查找,否则返回null
if(!bloomFilter.mightContain(name)){
logger.debug("不存在name为 "+ name +" 的数据");
return success(null);
}
// (1) Redis尝试获取数据
String json = redisUtil.getVal(name);
if (json != null) {
return success(new Gson().fromJson(json, Myuser.class));
} else {
// (2) Redis无数据,从MySQL获取数据,若存在数据则缓存到Redis
Myuser myuser = myuserDao.getUserByName(name);
if (myuser != null) {
json = new Gson().toJson(myuser);
redisUtil.setVal(name, json);
}
return success(myuser);
}
}
}
5. 测试对比图
(1)120s内1W线程,初次查询,Redis无缓存
这个走的方法是localhost:8089/api/test/name01
,即没有BloomFilter的方法。
(2)120s内1W线程,Redis已有缓存(将近一般数据命中缓存的情况)
这个走的方法是localhost:8089/api/test/name01
,即没有BloomFilter的方法。此时应该HTTP请求中有将近一般的请求能够命中Redis缓存。
(3)120s内1W线程,Reids有缓存(近一半),且配有BloomFilter
这个走的方法是localhost:8089/api/test/name02
,有BloomFilter的方法。同样近一般HTTP请求命中Redis缓存。
6. 小结
根据上面3种情况的对比:
- 很明显有Redis缓存,HTTP响应要快不少
- 在有Redis缓存基础上,如果有BloomFilter,那么会更快。
由于不想让电脑一直90多度,所以只简单测了120s内1W线程的情况。感兴趣的可以直接去我的github拉代码和测试文件跑跑看别的情况什么的。