一、为什么要使用Pipeline
Redis是采用基于C/S模式的请求/响应协议的TCP服务器。因为redis具有很高的吞吐量,所以redis的性能主要体现在网络状况上。如果网络状况不好,每次请求都会出现轻微的延迟和阻塞,在大量请求中,这种延迟的影响会很大。
Pipeline可以将一组redis命令打包无阻塞并按顺序发送到redis服务器上,这样可以节省大量请求的往返时间。 还有一点要注意的是,Pipeline并不能保证原子性,即Pipeline执行的内容可能会被其他客户端或是线程的指令"插队",若想要原子性操作,需要使用事务。
二、如何使用Pipeline
<!--依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Spring中通过RedisTemplate.executePipelined使用Pipeline执行命令
函数提供了两种回调方式: SessionCalback/RedisCallback
主要的区别是:SessionCalback封装的更好,使用会更方便一点,通常优先选择。
性能测试:
@Component
public class RedisUtil {
// 循环往redis插入数据
@Autowired
private RedisTemplate redisTemplate;
public void executePipelined(Map<String, String> param, long seconds) {
redisTemplate.executePipelined(new SessionCallback<Object>() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
for (Map.Entry<String, String> entry : param.entrySet()) {
operations.opsForValue().set(entry.getKey(), entry.getValue(), seconds);
}
//参数回调必须返回null,否则将抛出异常,可参考源码。
return null;
}
});
}
}
@SpringBootTest
@Slf4j
public class RedisPipelineTest {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedisUtil redisUtil;
@Test
public void test() {
long seconds = 10;
Map<String, String> mapA = new HashMap<>(100);
for (int i=0; i< 100; ++i) {
mapA.put("a" + i, "aa" + i);
}
Map<String, String> mapB = new HashMap<>(100);
for (int i=0; i< 100; ++i) {
mapB.put("b" + i, "bb" + i);
}
StopWatch watchA = new StopWatch("noPipeline");
watchA.start();
for (Map.Entry<String, String> entry : mapA.entrySet()) {
redisTemplate.opsForValue().set(entry.getKey(), entry.getValue(), seconds);
}
watchA.stop();
StopWatch watchB = new StopWatch("pipeline");
watchB.start();
redisUtil.executePipelined(mapB, seconds);
watchB.stop();
log.info("【noPipeline】 | 耗时: ({})", watchA.getLastTaskTimeMillis());
log.info("【pipeline】 | 耗时: ({})", watchB.getLastTaskTimeMillis());
}
}
最后的执行结果:
可以看出使用Pipeline的性能提升还是挺大的。但是需要注意的是,如果Pipeline里的命令过多的话,也会造成网络阻塞的,实际中,可以根据业务情况拆分成多个小的Pipeline来执行。