该栏目会系统的介绍 Redis 的知识体系,共分为相关概念、操作指令、主从复制等模块
缓存穿透
问题描述
:key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会压到数据源,从而可能压垮数据源解决方案
- 对空值缓存
- 设置白名单
- 进行实时监控
缓存击穿
问题描述
:key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮解决方案
- 预先设置热门数据
- 实时调整
缓存雪崩
问题描述
:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮解决方案
- 构建多级缓存架构
- 设置过期标志更新缓存
- 将缓存失效时间分散开
分布式锁
问题描述
:用来控制多同服务器访问共享资源的互斥机制实现
@Test
public void testLock() {
// 定义键,用来模拟锁住每个商品
String goodsId = "25";
String lockKey = "lock:" + goodsId;
// 使用UUID防误删
String uuid = UUID.randomUUID().toString();
final Boolean lock = stringOps.setIfAbsent(lockKey, uuid, 3, TimeUnit.SECONDS);
if (lock) {
final Object value = stringOps.get("num");
if (StringUtils.isEmpty(value)) {
return;
}
int num = Integer.parseInt(value + "");
stringOps.set("num", String.valueOf(++num));
// 使用lua脚本来解锁
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then "
+ "return redis.call('del', KEYS[1]) else return 0 end";
final DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
redisScript.setScriptText(script);
redisScript.setResultType(Long.class);
redisTemplate.execute(redisScript, Collections.singletonList(lockKey), uuid);
} else {
try {
Thread.sleep(1000);
testLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}