Redis与客户端是通过TCP协议进行沟通的,这代表着执行一条命令,都和客户端建立tcp连接,执行命令,然后发返回结果,释放连接。如果在大量执行执行命令,其中的消耗也不可小觑。Redis引入了Pineline技术,实际上就是某一客户端把多个redis操作缓存起来,一并发送到redis执行,最后结果也打包返回。
Spring中的RedisTemplate也提供了对pipeline的支持,下面使用RedisTemplate做普通redis操作和pipeline操作的耗时对比:
package com.learning.systemservice;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.learning.entity.model.Community;
import com.learning.systemservice.dao.CommunityDao;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@SpringBootTest
@Slf4j
class RedisPipeLineTest {
@Autowired
@Qualifier("jsonRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
@Autowired
private CommunityDao communityDao;
@Autowired
private ObjectMapper objectMapper;
private Map<String, Community> collect;
/**
* 查询全国的社区信息,大约有六十多万,并转换成List<Entry<JsonString,Community>>的形式
*/
@BeforeEach
void queryData() {
List<Community> communities = communityDao.queryAll(null);
collect = communities.stream().collect(Collectors.toMap(record -> {
try {
return objectMapper.writeValueAsString(record);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}, record -> record));
log.info("total records:" + collect.size());
}
/**
* 操作前清空redis数据库
*/
@BeforeEach
void clearRedisData() {
redisTemplate.execute((RedisCallback<Object>) connection -> {
connection.flushAll();
return null;
});
}
/**
* 使用循环设置redis,key是community_id,value是json
*/
@Test
void TestRedisLoopSet() {
long l1 = System.currentTimeMillis();
collect.forEach((key, val) -> {
redisTemplate.opsForValue().set("community_" + val.getId(), key);
});
long l2 = System.currentTimeMillis();
log.info("time:" + (l2 - l1));
}
/**
* 使用pipeline设置redis,key是community_id,value是json
*/
@Test
void TestRedisPipeLineSet() {
long l1 = System.currentTimeMillis();
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
collect.forEach((json, obj) -> {
connection.stringCommands().set(("community_" + obj.getId()).getBytes(StandardCharsets.UTF_8), json.getBytes(StandardCharsets.UTF_8));
});
return null;
});
long l2 = System.currentTimeMillis();
log.info("time:" + (l2 - l1));
}
}
循环set结果:488秒
...
2021-05-23 20:49:01.242 INFO 14384 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-05-23 20:49:02.585 INFO 14384 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2021-05-23 20:49:06.329 INFO 14384 --- [ main] c.l.systemservice.RedisPipeLineTest : total records:632599
2021-05-23 20:57:16.105 INFO 14384 --- [ main] c.l.systemservice.RedisPipeLineTest : time:488267
pipeline结果:4.2秒
...
2021-05-23 21:04:40.439 INFO 9300 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-05-23 21:04:41.694 INFO 9300 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2021-05-23 21:04:45.490 INFO 9300 --- [ main] c.l.systemservice.RedisPipeLineTest : total records:632599
2021-05-23 21:04:51.264 INFO 9300 --- [ main] c.l.systemservice.RedisPipeLineTest : time:4299