简单说一下背景
在高并发场景下对redis缓存进行操作,redis缓存失效,大量请求瞬间穿透到DB。
我们先看一下此种场景下这样写的问题
public void update(List<SpuInfoList> SpuInfoList) {
if (CollectionUtils.isEmpty(SpuInfoList) ) {
return;
}
int expire = RandomUtils.nextInt(0, RANDOM_RANGE);
String cacheKey = "spuInfo_list";
try {
List<String> resultList = SpuInfoList.stream().filter(Objects::nonNull)
.map(JsonUtils::toJson).collect(Collectors.toList())
try {
jedis.del(cacheKey);
jedis.rpush(cacheKey, resultList);
} finally {
jedis.expire(cacheKey, expire);
}
}
} catch (Exception e) {
……
}
}
在高并发场景下A、B两个线程 穿透到数据库;A获取到信息更新缓存;我们的缓存使用list这种数据结构去存储。A执行del删除key 并且rpush到缓存中。此时B也进入更新方法,执行del将A更新的信息删除……
修改方案如下:
如图所示 我们在更新缓存的时候需要增加一个分布式锁。
抢占到锁的执行则进行更新;
// 获取分布式锁,更新对应缓存,缓存2分钟, 不删除, 此处异常不需要监控
String lockKey = String.format("simplelock_", cacheKey)
jedis.set(lockKey,NX,EX,expire);
try {
if (jedis.exist(lockey)) {
List<String> resultList = rerankSearchResultList.stream().filter(Objects::nonNull)
.map(JsonUtils::toJson).collect(Collectors.toList());
jedis.del(cacheKey);
try {
jedis.rpush(cacheKey, resultList);
} finally {
jedis.expire(cacheKey, expire);
}
}
} catch (Exception e) {
}