Springboot2.x 集成 jedis和spring-boot-starter-data-redis的性能测试比较(Jedis完胜:附带源码)
- 1. pom文件引入jedis和spring-boot-starter-data-redis的依赖
- 2. 其他依赖的引入(Swagger)
- 3. Jedis配置类
- 4. Jedis及spring-boot-starter-data-redis的配置信息
- 5. Swagger配置类
- 5. 编写测试相关类
- 6. 测试
- 6.1 插入数据测试
- 6.2 读取数据测试
- 6.3 多线程读取数据测试
- 7. 结论
温馨提示:
本文配套代码:https://gitee.com/guduwuhen/springboot2-lesson/tree/master/redispro
1. pom文件引入jedis和spring-boot-starter-data-redis的依赖
<properties>
<java.version>1.8</java.version>
<jedis.version>2.9.0</jedis.version>
<fastjson.version>1.2.68</fastjson.version>
<guava.version>28.2-jre</guava.version>
</properties>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Springboot 使用的是2.2.4.RELEASE版本。
2. 其他依赖的引入(Swagger)
如下是完整的pom文件代码:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ieslab.powergrid</groupId>
<artifactId>redispro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demosvr</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<jedis.version>2.9.0</jedis.version>
<fastjson.version>1.2.68</fastjson.version>
<guava.version>28.2-jre</guava.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- 热部署时使用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- set/get方法免写,需要安装idea的插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Jedis配置类
RedisConfiguration.java
package com.test.redis.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/** <p>Title: RedisConfiguration </p>
* <p>Description: 用户rest接口类,测试demo使用</p>
*
* @author binge
* @date 2020-2-20 下午7:15:30
* @version V1.0
*/
@Configuration
public class RedisConfiguration {
@Bean(name= "jedis.pool")
@Autowired
public JedisPool jedisPool(@Qualifier("jedis.pool.config") JedisPoolConfig config,
@Value("${jedis.pool.host}")String host,
@Value("${jedis.pool.port}")int port) {
return new JedisPool(config, host, port);
}
@Bean(name= "jedis.pool.config")
public JedisPoolConfig jedisPoolConfig (@Value("${jedis.pool.config.maxTotal}")int maxTotal,
@Value("${jedis.pool.config.maxIdle}")int maxIdle,
@Value("${jedis.pool.config.maxWaitMillis}")int maxWaitMillis) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMaxWaitMillis(maxWaitMillis);
return config;
}
}
4. Jedis及spring-boot-starter-data-redis的配置信息
spring:
redis:
#数据库索引
database: 0
host: 192.168.22.150
port: 6379
lettuce:
pool:
#最大连接数
max-active: 100
#最大阻塞等待时间(负数表示没限制)
max-wait: 5000
#最大空闲
max-idle: 500
#最小空闲
min-idle: 8
#连接超时时间
timeout: 10000
jedis :
pool :
host : 192.168.22.150
port : 6379
config :
maxTotal: 1000
maxIdle: 1000
maxWaitMillis : 100000
5. Swagger配置类
package com.test.redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/** <p>Title: SwaggerConfig </p>
* <p>Description: Swagger配置类</p>
*
* @author binge
* @date 2020-2-20 下午7:15:30
* @version V1.0
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket creatApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()) // 指定构建api文档的详细信息的方法,下面会有实现:apiInfo()
.select()
// 指定要生成api接口的包路径,这里把controller作为包路径,生成controller中的所有接口
.apis(RequestHandlerSelectors.basePackage("com.test.redis.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Spring Boot集成Swagger2接口测试")
.description("生成的接口如下")
.version("1.0")
.contact(new Contact("斌哥","","houpeibin@126.com"))
.build();
}
}
5. 编写测试相关类
TestController.java
package com.test.redis.controller;
import com.test.redis.entity.Result;
import com.test.redis.entity.TestDataEntity;
import com.test.redis.service.TestAsyncService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import java.util.*;
import java.util.Map.Entry;
/** <p>Title: TestController </p>
* <p>Description: 测试redis</p>
*
* @author binge
* @date 2020-2-20 下午7:15:30
* @version V1.0
*/
@RestController
@Slf4j
@Api(tags="redis性能测试")
public class TestController {
@Autowired
private JedisPool jedisPool;
@Autowired
StringRedisTemplate redisTemplate;
@Autowired
TestAsyncService testAsyncService;
@RequestMapping("del")
@ApiOperation(value="删除所有库",notes="删除所有库")
public Result del(){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.flushAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
//返还到连接池
jedis.close();
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("insertStringData")
@ApiOperation(value="单个String数据插入",notes="单个String数据插入")
@ApiImplicitParams({
@ApiImplicitParam(name = "num", value = "插入条数", required = true, dataType = "Int", paramType="query"),
@ApiImplicitParam(name = "type", value = "数据类型", required = true, dataType = "String", paramType="query")
})
public Result insertStringData(int num, String type){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
for(int i=0; i<num; i++){
jedis.set(TestDataEntity.getKey(i, type), TestDataEntity.getTestStringData(type));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//返还到连接池
jedis.close();
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("insertStringDataPipelined")
@ApiOperation(value="jedis方式批量插入String数据",notes="jedis方式批量插入String数据")
public Result insertStringDataPipelined(@ApiParam(name="num",value="插入条数",required = true)@RequestParam int num,
@ApiParam(name="type",value="数据类型",required = true)@RequestParam String type){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
try {
//使用管道方式,性能比单次获取性能高
jedis = jedisPool.getResource();
Pipeline pipeline = jedis.pipelined();
Map<String, Response<String>> map = new HashMap<>();
for(int i=0; i<num; i++){
Response<String> sResponse= pipeline.set(TestDataEntity.getKey(i, type),TestDataEntity.getTestStringData(type));
map.put(String.valueOf(i), sResponse);
}
pipeline.sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
//返还到连接池
jedis.close();
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("insertStringDataPipelinedByRedisTemplate")
@ApiOperation(value="redisTemplate方式批量插入String数据",notes="redisTemplate方式批量插入String数据")
public Result insertStringDataPipelinedByRedisTemplate(@ApiParam(name="num",value="插入条数",required = true)@RequestParam int num,
@ApiParam(name="type",value="数据类型",required = true)@RequestParam String type) {
long startTime = System.currentTimeMillis();
/* 插入多条数据 */
redisTemplate.executePipelined(new SessionCallback<Object>() {
@Override
public <K, V> Object execute(RedisOperations<K, V> redisOperations) throws DataAccessException {
for(int i=0;i<num;i++){
redisTemplate.opsForValue().set(TestDataEntity.getKey(i, type),TestDataEntity.getTestStringData(type));
}
return null;
}
});
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("getDataByKey")
@ApiOperation(value="根据key关键字获取所有key",notes="根据key关键字获取所有key")
public Result getDataByKey(@ApiParam(name="key",value="key关键字",required = true)@RequestParam String key){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
Set<String> keys;
try {
jedis = jedisPool.getResource();
keys = jedis.keys(key);
log.info(".......keys:" + keys.size());
} finally {
//返还到连接池
jedis.close();
}
return Result.ok((System.currentTimeMillis() - startTime) + ":数据个数:" + keys.size());
}
@RequestMapping("getValueBykey")
@ApiOperation(value="根据key过滤获取数据",notes="根据key过滤获取数据")
public Result getValueBykey(@ApiParam(name="key",value="过滤条件",required = true)@RequestParam String key){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//使用管道方式,性能比单次获取性能高
Map<String, String> map = new HashMap<>();
Set<String> keys = jedis.keys(key);
for(String ketTmp :keys){
try {
String sResponse= jedis.get(ketTmp);
map.put(ketTmp,sResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
long haoshi = System.currentTimeMillis() - startTime;
System.out.println("个数:" + map.size() + ";耗时:" + haoshi+ ";大小:" + map.toString().getBytes().length/1024);
} finally {
//返还到连接池
jedis.close();
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("getDataByPipelined")
@ApiOperation(value="根据num,type过滤获取数据",notes="根据num,type过滤获取数据")
public Result getDataByPipelined(@ApiParam(name="num",value="查询条数",required = true)@RequestParam int num,
@ApiParam(name="type",value="数据类型",required = true)@RequestParam String type){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
Map<String, Response<String>> map = null;
try {
jedis = jedisPool.getResource();
//使用管道方式,性能比单次获取性能高
Pipeline pipeline = jedis.pipelined();
map = new HashMap<>();
for(int i=0;i<num;i++){
try {
Response<String> sResponse= pipeline.get(TestDataEntity.getKey(i, type));
map.put(String.valueOf(i), sResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
pipeline.sync();
int i = num-10;
for (Entry<String, Response<String>> entry : map.entrySet()) {
Response<String> sResponse=(Response<String>)entry.getValue();
if(i<num){
System.out.println(entry.getKey()+"-----" + sResponse.get());
}
++i;
}
System.out.println(map.size() + ":" + map.toString().getBytes().length/1024);
} finally {
//返还到连接池
jedis.close();
}
return Result.ok((System.currentTimeMillis() - startTime) + ":数据个数:" + map.size() + ":" + map.toString().getBytes().length/1024);
}
@RequestMapping("getDataByPipelinedAndPipelineKey")
@ApiOperation(value="根据key过滤获取数据",notes="根据key过滤获取数据")
public Result getDataByPipelinedAndPipelineKey(@ApiParam(name="key",value="过滤条件",required = true)@RequestParam String key){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//使用管道方式,性能比单次获取性能高
Pipeline pipeline = jedis.pipelined();
Map<String, Response<String>> map = new HashMap<>();
Response<Set<String>> keys = pipeline.keys(key);
pipeline.sync();
Set<String> sets = keys.get();
for(String ketTmp :sets){
try {
Response<String> sResponse= pipeline.get(ketTmp);
map.put(ketTmp,sResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
pipeline.sync();
long haoshi = System.currentTimeMillis() - startTime;
System.out.println("个数:" + map.size() + ";耗时:" + haoshi+ ";大小:" + map.toString().getBytes().length/1024);
} finally {
//返还到连接池
jedis.close();
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("getDataByPipelinedAndJedisKey")
@ApiOperation(value="根据key过滤获取数据",notes="根据key过滤获取数据")
public Result getDataByPipelinedAndJedisKey(@ApiParam(name="key",value="过滤条件",required = true)@RequestParam String key){
long startTime = System.currentTimeMillis();
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
//使用管道方式,性能比单次获取性能高
Pipeline pipeline = jedis.pipelined();
Map<String, Response<String>> map = new HashMap<>();
Set<String> sets = jedisPool.getResource().keys(key);
for(String ketTmp :sets){
try {
Response<String> sResponse= pipeline.get(ketTmp);
map.put(ketTmp,sResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
pipeline.sync();
int i = sets.size()-10;
for (Entry<String, Response<String>> entry : map.entrySet()) {
Response<String> sResponse=(Response<String>)entry.getValue();
if(i<sets.size()){
System.out.println(entry.getKey()+"-----" + sResponse.get());
}
++i;
}
System.out.println(map.size() + ":" + map.toString().getBytes().length/1024);
} finally {
//返还到连接池
jedis.close();
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("getDataByPipelinedByRedisTemplate")
@ApiOperation(value="RedisTemplate根据key过滤获取数据",notes="RedisTemplate根据key过滤获取数据")
public Result getDataByPipelinedByRedisTemplate(@ApiParam(name="key",value="过滤条件",required = true)@RequestParam String key){
long startTime = System.currentTimeMillis();
try {
Set<String> sets = jedisPool.getResource().keys(key);
List<String> keyList = new ArrayList<>();
for(String ketTmp :sets){
keyList.add(ketTmp);
}
List<Object> obj = redisTemplate.executePipelined((RedisCallback<String>) redisConnection -> {
StringRedisConnection stringRedisConnection = (StringRedisConnection) redisConnection;
for (String keyTmp : keyList) {
stringRedisConnection.get(keyTmp);
}
return null;
});
System.out.println(obj.size() + ":" + obj.toString().getBytes().length/1024);
} finally {
//返还到连接池
}
return Result.ok(System.currentTimeMillis() - startTime);
}
@RequestMapping("startAsyn")
@ApiOperation(value="启动异步线程并发获取数据",notes="启动异步线程并发获取数据")
public Result startAsyn(@ApiParam(name="num",value="线程个数",required = true)@RequestParam int num,
@ApiParam(name="key",value="过滤条件",required = true)@RequestParam String key){
long startTime = System.currentTimeMillis();
for (int i=0; i<num; ++i){
testAsyncService.startAsyn(key);
}
return Result.ok(System.currentTimeMillis() - startTime);
}
}
Result.java 返回结构
package com.test.redis.entity;
/** <p>Title: PersonService </p>
* <p>Description: 通用Rest请求返回结构 </p>
*
* @author bingge
* @date 2020-2-20 下午7:15:30
* @version V1.0
*/
public class Result {
//服务器返回的状态码(主要给程序员看)。例如 : 200 : 请求成功, 500 : 服务器内部错误,400 : 未知错误
private Integer code;
//返回码 1:成功 10000:系统错误 10001:参数错误 ...
private Integer status;
// 服务器的错误信息 ,主要返回给用户看
private String msg;
// 服务器返回的数据
private Object data;
public Result() {
}
//返回操作成功
public static Result ok() {
return ok(null);
}
//返回操作成功
public static Result ok(Object data) {
Result result = new Result();
result.setCode(200);
result.setStatus(1);
result.setMsg("请求成功");
result.setData(data);
return result;
}
//返回操作成功
public static Result error() {
return error("请求失败");
}
//返回操作成功
public static Result error(Integer code, Integer status, String msg) {
Result result = new Result();
result.setCode(code);
result.setStatus(status);
result.setMsg(msg);
return result;
}
//返回操作成功
public static Result error(String msg) {
return error(500,0, msg);
}
//返回操作成功
public static Result error(ErrorStatus errorStatus) {
return error(500,errorStatus.value(), errorStatus.getMessage());
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
全局异常捕捉处理GlobleExceptionHandler.java
package com.test.redis.utils;
import com.test.redis.entity.MyException;
import com.test.redis.entity.Result;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/** <p>Title: GlobleExceptionHandler </p>
* <p>Description: 全局异常捕捉处理</p>
*
* @author binge
* @date 2020-2-20 下午7:15:30
* @version V1.0
*/
@ControllerAdvice
public class GlobleExceptionHandler {
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Result errorHandler(Exception ex) {
//判断异常的类型,返回不一样的返回值
if(ex instanceof MissingServletRequestParameterException){
return Result.error(400, 0, "全局异常捕捉:缺少必需参数:"
+((MissingServletRequestParameterException) ex).getParameterName());
}
else if(ex instanceof MyException){
return Result.error(400, 0, "全局异常捕捉:这是自定义异常");
}
return Result.error(400, 0, "全局异常捕捉:未知异常");
}
}
线程池配置AsyncConfiguration.java
package com.test.redis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
/** <p>Title: PersonService </p>
* <p>Description: 线程池配置</p>
*
* @author houpeibin
* @date 2020-2-20 下午7:15:30
* @version V1.0
*/
@Configuration
@EnableAsync // 启用异步任务
public class AsyncConfiguration {
// 声明一个线程池(并指定线程池的名字)
@Bean("taskExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数5:线程池创建时候初始化的线程数
executor.setCorePoolSize(50);
//最大线程数5:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
executor.setMaxPoolSize(500);
//缓冲队列500:用来缓冲执行任务的队列
executor.setQueueCapacity(500);
//允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
executor.setKeepAliveSeconds(60);
//线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
executor.setThreadNamePrefix("DailyAsync-");
executor.initialize();
return executor;
}
}
TestDataEntity.java
package com.test.redis.entity;
import com.alibaba.fastjson.JSONObject;
import java.util.UUID;
/**
* 测试数据类
*/
public class TestDataEntity {
static String testStringData;
static{
StringBuffer sb = new StringBuffer();
for(int i=0;i<100;++i){
sb.append("测试");
}
testStringData = sb.toString();
}
public static String getTestStringData(String type){
JSONObject obj = new JSONObject();
obj.put("type",type);
obj.put("uuid",UUID.randomUUID());
obj.put("data",testStringData);
return obj.toString();
}
public static String getKey(int index, String type){
return "rtd:" + index + ":" + type;
}
}
6. 测试
打开http://localhost:8080/swagger-ui.html#/
6.1 插入数据测试
首先从http://localhost:8080/swagger-ui.html#/ 测试界面中,找到“单个String数据插入”接口:/insertStringData
点击“Try it out”,
执行结果在图形的下面,如下图
依照此方法依次测试insertStringDataPipelined和insertStringDataPipelinedByRedisTemplate接口
单位:ms
个数 | jedis单次写入 | jedis批量写入 | RedisTemplate批量写入 |
3000个 | 192 | 28 | 54 |
30000个 | 2432 | 242 | 539 |
100000个 | 6061 | 762 | 1988 |
300000个 | 19203 | 2262 | 7015 |
一个数据的长度为:
{"data":"测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试","type":"1","uuid":"aa5b34ba-dd43-4d93-a795-485a0683be7a"}
6.2 读取数据测试
依照此方法依次测试getValueBykey 和getDataByPipelinedAndPipelineKey 、getDataByPipelinedByRedisTemplate接口
单位:ms
个数 | jedis单次读取 | jedis批量读取 | RedisTemplate批量读取 |
3000个 | 489 | 224 | 308 |
30000个 | 2030 | 331 | 891 |
100000个 | 6530 | 689 | 2247 |
300000个 | 18089 | 1622 | 9253 |
6.3 多线程读取数据测试
先插入3000条数据类型为4的数据,便于并发测试:
然后启动5个线程:
查看后台日志:
依次按照如下表格的次数进行测试,记录如下:
个数 | 平均耗时 |
5个 | 162 |
10个 | 336 |
20个 | 668 |
50个 | 1679 |
100个 | 1399 |
200个 | 1604 |
500个 | 1506 |
并发测试时,因此同时启动100线程占用时间,一旦线程运行之后,访问redis的时间基本都在1000-2000ms之间。
7. 结论
通过读取对比:
- 单次读写,性能最差
- jedis性能比RedisTemplate的性能好3倍,并且随着数据量的增大,倍数也成指数增加
因此优先选择jedis
,因为他在性能方面完胜RedisTemplate
并发测试:
- 并发访问时,对于多线程的开销较大,而对于并发访问redis的性能影响较小。