缓存击穿
【摘要】 在类似于电商系统中,会存在这样一种情况,比如某个冷门的商品,平时没有多少人去访问,然后公司将这些性价比高的冷门商品进行挖掘出来然后将这些商品去交给热门的大主播来进行带货,大家看了主播的讲解后觉得东西确实很好,导致一瞬间的流程激增又比如某个顶流的明星突然宣布了爆炸性的新闻,比如结婚了、离婚了、劈腿了等等,大家会同一时间去查看类似的新闻,系统的流量同样会激增,前几年微博就是类似在这种情况下宕机了...
在类似于电商系统中,会存在这样一种情况,比如某个冷门的商品,平时没有多少人去访问,然后公司将这些性价比高的冷门商品进行挖掘出来
然后将这些商品去交给热门的大主播来进行带货,大家看了主播的讲解后觉得东西确实很好,导致一瞬间的流程激增
又比如某个顶流的明星突然宣布了爆炸性的新闻,比如结婚了、离婚了、劈腿了等等,大家会同一时间去查看类似的新闻,系统的流量同样会激增,前几年微博就是类似在这种情况下宕机了。
在这种情况下,访问数据库时就会造成的数据库的压力过大,很可能会直接将数据库宕机掉
有人说了,这时加个Redis缓存来缓解数据库的压力不就好了吗?
既然这样,那就模拟一下写一段伪代码
public String getData(String id){
RedisTemplate<String,String> redisTemplate = redisCache.getInstance();
String cachedValue = redisTemplate.opsForValue().get(id);
if (StringUtil.isEmpty(cachedValue)) {
Program program = programMapper.selectById(id);
if (Objects.nonNull(program)) {
redisTemplate.opsForValue().set(id,JSON.toJSONString(program));
cachedValue = JSON.toJSONString(program);
}
}
return cachedValue;
};
首先从redis中查看是否存在,如果不存在则从数据库中查询,接着将查询出的数据放在redis中,最后将数据返回
不少人就是直接这么用的,到这里先不急着往下看,我们可以先仔细想一想,这么写会不会存在问题?
潜在的问题
这种写法,在小公司或者并发量不高的情况下没有什么问题,但是在海量的并发场景下就会存在很严重的问题!
我们再好好分析这段代码
public String getData(String id){
RedisTemplate<String,String> redisTemplate = redisCache.getInstance();
String cachedValue = redisTemplate.opsForValue().get(id);
//有一种极大的可能性,就是大量的请求都集中在这里判断redis中都是不存在的
if (StringUtil.isEmpty(cachedValue)) {
//大量的请求很可能会执行到这里
Program program = programMapper.selectById(id);
if (Objects.nonNull(program)) {
redisTemplate.opsForValue().set(id,JSON.toJSONString(program));
cachedValue = JSON.toJSONString(program);
}
}
return cachedValue;
};
因为都是并发的请求,当一瞬间大量的请求过来时,很有可能大量的请求都是在查询redis中的数据判断是不存在的,那么还是最终都去查询数据库了,虽然第一次请求从数据库中查询,然后放入到redis中,但其他的请求已经执行了redis判断的阶段,也已经去查询数据库了
也就是说这时加缓存完全没啥用了,最终导致的结果是虽然缓存中有数据,但还是大量的请求执行到了数据库层面,这就是常说的 缓存击穿!
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)