查看原文
其他

Redis缓存雪崩、缓存击穿、缓存穿透 及 常见缓存模式

邋遢的流浪剑客 搜云库技术团队 2020-02-05

点击上方“搜云库技术团队”关注,选择“设为星标

回复“1024”或“面试题”获取4T架构师资料


一、缓存雪崩

1、什么是缓存雪崩?

如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩

由于原有缓存失效,新缓存未到期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机

2、有什么解决方案来防止缓存雪崩?

1、加锁排队

mutex互斥锁解决,Redis的SETNX去set一个mutex key,当操作返回成功时,再进行加载数据库的操作并回设缓存,否则,就重试整个get缓存的方法

最新粉丝福利

腾讯云1核2G,1年88元,3年268元限量秒杀

2、数据预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据。可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key

3、双层缓存策略

C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期

4、定时更新缓存策略

实效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存

5、设置不同的过期时间,让缓存失效的时间点尽量均匀

二、缓存击穿

1、什么是缓存击穿?

在平常高并发的系统中,大量的请求同时查询一个key时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿

2、会带来什么问题

会造成某一时刻数据库请求量过大,压力剧增

3、如何解决

上面的现象是多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个互斥锁来锁住它

其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存

三、缓存穿透

1、什么是缓存穿透?

缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到对应key的value,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询)。这样请求就绕过缓存直接查数据库

2、有什么解决方案来防止缓存穿透?

1、缓存空值

如果一个查询返回的数据为空(不管是数据不存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过5分钟。通过这个设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库

2、采用布隆过滤器BloomFilter

优势:占用内存空间很小,位存储;性能特别高,使用key的hash判断key存不存在

将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力

在缓存之前在加一层BloomFilter,在查询的时候先去BloomFilter去查询key是否存在,如果不存在就直接返回,存在再去查询缓存,缓存中没有再去查询数据库

四、常见的几种缓存模式

1、Cache Aside

应用在查询数据的时候,先从缓存Cache中读取数据,如果缓存中没有,则再从数据库中读取数据,得到数据库的数据之后,将这个数据也放到缓存Cache中

如果应用要更新某个数据,也是先去更新数据库中的数据,更新完成之后,则通过指令让缓存Cache中的数据失效

1、这里为什么不让更新操作在写完数据库之后,紧接着去把缓存Cache中的数据也修改了呢?

主要是因为这样做的话,就有2个写操作的事件了,担心在并发的情况下会导致脏数据,举个例子:假如同时有2个请求,请求A和请求B,并发的执行。请求A是要去读数据,请求B是要去更新数据。初始状态缓存中是没有数据的,当请求A读到数据之后,准备往回写的时候,此刻,请求B正好要更新数据,更新完了数据库之后,又去把缓存更新了,那请求A再往缓存中写的就是旧数据了,属于脏数据

2、那么Cache Aside模式就没有脏数据问题了吗?

在极端情况下也可能会产生脏数据。例如,同时有2个请求,请求A和请求B,并发的执行。请求A是要去读数据,请求B是要去写数据。假如初始状态缓存中没有这个数据,那请求A发现缓存中没有数据,就会去数据库中读数据,读到了数据准备写回缓存中,就在这个时候,请求B是要去写数据的,请求B在写完数据库的数据之后,又去设置了缓存失效。这个时候,请求A由于在数据库中读到了之前的旧数据,开始往缓存中写数据了,此时写进入的就也是旧数据。那么最终就会导致,缓存中的数据与数据库的数据不一致,造成了脏数据

2、Read/Write Through

应用要读数据和更新数据都直接访问缓存服务

缓存服务同步地将数据更新到数据库

出现脏数据的概率较低,但是就强依赖缓存,对缓存服务的稳定性有较大要求

3、Write Behind模式

应用要读数据和更新数据都直接访问缓存服务 缓存服务异步地将数据更新到数据库(通过异步任务) 速度快,效率会非常高,但是数据的一致性比较差,还可能会有数据的丢失情况,实现逻辑也较为复杂
来源:http://suo.im/5jdgcd
近期技术热文
1、牛逼!96秒100亿,阿里到底做了什么? 
2、深入理解 Spring Cloud 核心组件 底层原理 
3、如何设计权限管理模块,超详细,设计17个表 
4、面试官问:一个 TCP 连接可以发多少个 HTTP 请求? 
5、使用 Redis 如何实现点赞,取消点赞呢? 
6、拼多多面试:如何用 Redis 统计独立用户访问量?

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存