SpringRedisTemplate和RedisTemplate区别

这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战

前言

也是今天遇到的一个问题, 新搭建的项目使用SpringRedisTemplate遇到的一些问题记录一下, 也把相关的知识总结归纳一下.

问题描述

两个问题, 1. 自测的时候发现调用stringRedisTemplate.opsForValue().get(key) 耗时非常长,一直卡住不动. 2. 序列化的问题

问题原因其实是一个比较低级的问题, 也是对一些框架的原理理解的有些偏差. 业务场景我们利用布隆过滤器去过滤一些URL, 但是布隆过滤器需要定期的过期(因为数据量比较大而且一直递增). 我们定义的是每个月一个布隆过滤器, 每个月第一笔请求的时候需要判断布隆过滤器是否存在. key: 设置为bloom:filter:202108 value: bloom:filter:202108 然后把value作为布隆过滤器的name, 在去判断布隆过滤器是否存在.

@Test
public void test() {

    String key = "bloom:filter:202108";
    stringRedisTemplate.opsForValue().set(key, key, 100l, TimeUnit.SECONDS);
    String  res = stringRedisTemplate.opsForValue().get(key);

    RBloomFilter<String> filter = redisson.getBloomFilter(key);
    filter.tryInit(100000000, 0.001);
    filter.add("iyixh");

    System.out.println(filter.contains("123as"));
    System.out.println(res);
}
复制代码

执行后发现, 有两个key, 一个是bloom:filter:202108,一个是bloom过滤器的配置{bloom:filter:202108}:config,

image.png

在看下每个key对应的大小,bloom:filter:202108 这个key的redis值value似乎变成了bloomFilter的大小了.

image.png

DEBUG看下源码, 可以看到第一步只是构造函数, 有两个name,一个是过滤器的名称bloom:filter:202108, 一个是配置{bloom:filter:202108}:config

image.png

那么在看下初始化的方法:tryInit, 可以看到设置初始化值的时候其实是报错的, bloom过滤器我们知道底层的数据结构是bitmap数组,初始化的时候设置大小.168.23M, 在到底层就是C的代码了.

image.png

所以我们在设置缓存key的时候不能和布隆过滤器重名, 防止底层数据结构发生变更.

说说 redisTemplate 和 stringRedisTemplate

为什么会需要两个Template呢?有什么区别呢?

2.1. 比较

stringRedisTemplate

  1. 主要用来存储字符串,StringRedisSerializer的泛型指定的是String。当存入对象时,会报错 :can not cast into String
  2. 可见性强,更易维护。如果过都是字符串存储可考虑用StringRedisTemplate。

redisTemplate

  • 可以用来存储对象,但是要实现Serializable接口。
  • 以二进制数组方式存储,内容没有可读性。

image.png

2.2 redisTemplate序列化

spring-data-redis提供如下几种选择:

  • GenericToStringSerializer: 可以将任何对象泛化为字符串并序列化
  • Jackson2JsonRedisSerializer: 跟JacksonJsonRedisSerializer实际上是一样的
  • JacksonJsonRedisSerializer: 序列化object对象为json字符串
  • JdkSerializationRedisSerializer: 序列化java对象
  • StringRedisSerializer: 简单的字符串序列化

2.2.1 测试

@Test
public void testSerial(){
    User user = new User();
    user.setId(1001L);
    user.setName("测试");
    user.setAge(18);
    List<Object> list = new ArrayList<>();
    for(int i=0;i<200;i++){
        list.add(user);
    }
    JdkSerializationRedisSerializer jdkSerialize = new JdkSerializationRedisSerializer();
    GenericJackson2JsonRedisSerializer g = new GenericJackson2JsonRedisSerializer();
    Jackson2JsonRedisSerializer jackson2 = new Jackson2JsonRedisSerializer(List.class);

    Long j_s_start = System.currentTimeMillis();
    byte[] bytesJ = jdkSerialize.serialize(list);
    System.out.println("JdkSerializationRedisSerializer序列化时间:"+(System.currentTimeMillis()-j_s_start) + "ms,序列化后的长度:" + bytesJ.length);
    Long j_d_start = System.currentTimeMillis();
    jdkSerialize.deserialize(bytesJ);
    System.out.println("JdkSerializationRedisSerializer反序列化时间:"+(System.currentTimeMillis()-j_d_start));
    
    Long g_s_start = System.currentTimeMillis();
    byte[] bytesG = g.serialize(list);
    System.out.println("GenericJackson2JsonRedisSerializer序列化时间:"+(System.currentTimeMillis()-g_s_start) + "ms,序列化后的长度:" + bytesG.length);
    Long g_d_start = System.currentTimeMillis();
    g.deserialize(bytesG);
    System.out.println("GenericJackson2JsonRedisSerializer反序列化时间:"+(System.currentTimeMillis()-g_d_start));

    Long j2_s_start = System.currentTimeMillis();
    byte[] bytesJ2 = jackson2.serialize(list);
    System.out.println("Jackson2JsonRedisSerializer序列化时间:"+(System.currentTimeMillis()-j2_s_start) + "ms,序列化后的长度:" + bytesJ2.length);
    Long j2_d_start = System.currentTimeMillis();
    jackson2.deserialize(bytesJ2);
    System.out.println("Jackson2JsonRedisSerializer反序列化时间:"+(System.currentTimeMillis()-j2_d_start));
}
复制代码

image.png

2.2.2 总结

  • JdkSerializationRedisSerializer序列化后长度最小,Jackson2JsonRedisSerializer效率最高。
  • 如果综合考虑效率和可读性,牺牲部分空间,推荐key使用StringRedisSerializer,保持的key简明易读;value可以使用Jackson2JsonRedisSerializer
  • 如果空间比较敏感,效率要求不高,推荐key使用StringRedisSerializer,保持的key简明易读;value可以使用JdkSerializationRedisSerializer

最后

架构的过程其实就是不断比较取舍的过程, 不同的应用场景有不同的技术选型.

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享