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。