Springboot + Redis Pipeline Inserting

Redis本身是基于Request/Response协议的,正常情况下,客户端发送一个命令,等待Redis应答,Redis在接收到命令,处理后应答。

在这种情况下,如果同时需要执行大量的命令,那就是等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁的调用系统IO,发送网络请求。


为了提升效率,这时候Pipeline出现了,它允许客户端可以一次发送多条命令,而不等待上一条命令执行的结果,这和网络的Nagel算法有点像(TCP_NODELAY选项)。

不仅减少了RTT,同时也减少了IO调用次数(IO调用涉及到用户态到内核态之间的切换)。


客户端这边首先将执行的命令写入到缓冲中,最后再一次性发送Redis。

 

说的直白一点:

就是极大速度的提高了写入速度。

批量处理和单一处理等反馈,这两个模式是有本质不同的。

 

pom.xml Redis依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

配置类:

@Configuration
public class RedisConfig {
    private final LettuceConnectionFactory factory;

    public RedisConfig(LettuceConnectionFactory factory) {
        this.factory = factory;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        factory.setShareNativeConnection(false);
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }

    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    @Bean
    public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }

}

功能类:

    /**
     * usePipelinesAdd: Redis Set addition by using pipeline
     *
     * @param map of result set
     */
    public boolean usePipelinesAdd(String key, String Value) {
        stringRedisTemplate.executePipelined((RedisCallback<Object>) redisConnection -> {
            StringRedisConnection stringRedisConn = (StringRedisConnection) redisConnection;
       /** redis function */
            stringRedisConn.sAdd(key, value);            
            return null;
        });
        return true;
    }
这里:
stringRedisConn.sAdd(key, value);

是Redis Set集合的sadd方法,其他的操作方法很多,自己很容易探索。

 

讲几个容易踩雷的地方:

StringRedisTemplate继承RedisTemplate,但它们采用的序列化策略不同:

* StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
* RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。

采用的是RedisTemplate,在传递String类型的数据结构后,查看缓存会发现数据乱码现象。如下:

"\xac\xed\x00\x05t\x00?mykey"

需要修改RedisTemplate序列化策略:

RedisSerializer<String> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setHashValueSerializer(stringSerializer);

但是注意一点,由于采用了String的序列化策略,所以只接受value值类型为String的参数。

如此繁琐,所以日常开发还是推荐使用StringRedisTemplate。

 

 

 

  

 

posted @ 2020-08-25 09:31  KoenigSEA  阅读(201)  评论(0编辑  收藏  举报
Back to HOME