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

springboot和django并发处理能力对比_jedis

点击“Try it out”,

springboot和django并发处理能力对比_java_02


执行结果在图形的下面,如下图

springboot和django并发处理能力对比_spring_03


依照此方法依次测试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的数据,便于并发测试:

springboot和django并发处理能力对比_spring_04


然后启动5个线程:

springboot和django并发处理能力对比_redis_05


查看后台日志:

springboot和django并发处理能力对比_jedis_06

依次按照如下表格的次数进行测试,记录如下:

个数

平均耗时

5个

162

10个

336

20个

668

50个

1679

100个

1399

200个

1604

500个

1506

并发测试时,因此同时启动100线程占用时间,一旦线程运行之后,访问redis的时间基本都在1000-2000ms之间。

7. 结论

通过读取对比:

  1. 单次读写,性能最差
  2. jedis性能比RedisTemplate的性能好3倍,并且随着数据量的增大,倍数也成指数增加
    因此优先选择jedis,因为他在性能方面完胜RedisTemplate

并发测试:

  1. 并发访问时,对于多线程的开销较大,而对于并发访问redis的性能影响较小。