Springboot Redis SwitchDB + SwapDB
冷启动数据环境中,流程如下:
Start -> FlushDB -> LOAD Data from Oracle/MySQL -> Insert Data into Redis -> End
FlushDB这个时间点a,完成LOAD时间点b,完成Insert 时间点c。
也就是说在(c - a)这么长的时间内,用户是无法获取数据的,即数据空白期。
这是很影响用户体验的。
我们改善一下流程:
Start -> Select DB-sub -> FlushDB-sub -> LOAD Data from Oracle/MySQL -> Insert Data into Redis DB-sub -> SwapDB main & sub -> END
这样的话,我们只在最后一个swap的过程中会有一个数据空白期,但是swap执行速度极快,也就是说,空白期几乎没有。
用Springboot实现,则会使用到Redis的Select以及Swapdb
SELECT int SWAPDB int int
pom.xml:
<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(); } }
功能类:
public boolean insert() { stringRedisTemplate.executePipelined((RedisCallback<Object>) redisConnection -> { StringRedisConnection stringRedisConn = (StringRedisConnection) redisConnection; logger.info("[REDIS] Switching to DB[" + subDatabase + "]"); stringRedisConn.select(subDatabase); stringRedisConn.flushDb(); /** insert */ stringRedisConn.set(key,value); return null; }); return true; }
swapDB 只能用Jedis实现:
public void dbSwap() { Jedis jedis = new Jedis(host, port); jedis.auth(password); logger.info("[REDIS] Swapping DB[" + database + "] and DB[" + subDatabase + "]"); jedis.swapDB(database, subDatabase); }
注意一下,为了selectdb,在配置类中
factory.setShareNativeConnection(false);
不然会切换失败