Redis专栏目录
1.三种概念
(1)缓存雪崩
缓存同一时间大面积失效,所以后续请求大面积落到数据库上,造成数据库短时间内承受大量请求而崩掉
(2)缓存击穿
频繁访问的热点数据过期
(3)缓存穿透
缓存和数据库中都有没有数据,导致所有请求都落在数据库上。
2.解决方案(缓存雪崩)
(1)缓存雪崩理解
背景:通常我们为了保证缓存中的数据与数据库中的数据一致性,
会给 Redis 里的数据设置过期时间,
当缓存数据过期后,用户访问的数据如果不在缓存里,业务系统需要重新生成缓存,因此就会访问数据库,并将数据更新到 Redis 里。
问题:那么,
当大量缓存数据在同时过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃。因此,主要由两个原因造成:
-
大量数据同时过期
-
Redis故障宕机

(2)大量数据同时过期(四种方案)
-
随机过期时间:过期时间加上 随即数,避免同一时间过期 。
-
互斥锁:业务线程加 超时互斥锁 ,保证同时只有一个请求构建缓存 ( 例如1000并发时,突然redis缓存失效时请求发入数据库 。那么 缓存失效先锁住 ,然后 从数据库读取数据,再更新到Redis里。等有缓存了再解锁 , 当缓存构建完再释放锁) 。 若业务线程未获得锁请求,要么等待锁释放后重新读取缓存,要么返回空值或默认值 。
-
双Key策略(备份副本): 一个主key设置过期,一个备key不设置过期, 两者key不同但value一样 。 当业务线程访问不到主key时,就直接返回备key,然后更新缓存,同时更新主key和备key 。
-
后台更新缓存: 业务线程不再负责更新缓存,缓存也不设置有效期(内存紧张时淘汰部分),并将更新缓存的工作交由后台线程定时更新。 但"淘汰"到下一次更新期间,业务读取缓存失败返回空值,业务误认为数据丢失。解决方法有两种:
-
①后台不仅要负责定时更新缓存,而且还负责频繁检测缓存是否有效。若失效则立即读数据库再更新(检查时间长会导致用户尝试解获取空值, 用户体验一般)。
-
②业务线程发现缓存失效后, 通过消息队列发送一条消息通知后台线程更新缓存,后台收到消息后,在更新缓存前判断缓存是否存在,存在就不更新;不存在就读取数据库数据再更新。(这种方式相比第一种方式缓存的更新会更及时,用户体验也比较好)
-
(3)Redis宕机(两种方案)
-
服务熔断/请求限流机制:暂停业务对缓存访问,直接返回错误。以此降低数据库压力,等Redis恢复正常后再访问缓存。 直接熔断缓存服务,业务将无法工作。为了减少业务影响,采用 请求限流, 只将少部分请求发送到数据库处理,多余请求拒绝服务。等redis恢复正常把 缓存预热走完(提前将数据缓起来,而不是等待用户访问才来触发缓存构建),再解除请求限流。
-
构建Redis缓存高可靠集群:若缓存主节点宕机,从节点可切换成主节点继续服务。
3.解决方案(缓存击穿,缓存雪崩子集)
(1)缓存击穿理解
背景:
当某个热点数据过期(秒杀活动),大量请求直接访问数据库。常见原因有两种:
-
业务误操作:缓存和数据库中数据误删除。
-
恶意攻击:恶意大量访问不存在业务。
(2)解决方案(两种)
-
互斥锁(见上)
-
后台更新缓存(见上)
4.解决方案(缓存击穿)
(1)背景
数据既不在缓存,也不在数据库。
(2)解决方案(三种)
-
非法请求限制:API 入口处我们要判断求请求参数是否合理(有非法值、请求字段是否存在),然后返回错误。
-
缓存空值或默认值:针对频繁查询请求,设置空值或默认值
-
布隆过滤器: 查询布隆过滤器快速判断数据是否存在,若不存在则不需查找数据库。在写入数据库数据时,使用布隆过滤器做标记。这样下次查询数据是否在数据库时,只需要查询布隆过滤器,如果查询到数据没有被标记,说明不在数据库中。
【布隆过滤器原理】
布隆=bit数组(存储0/1) 和 多个哈希函数组成。在写入数据库时,布隆过滤器会记录标记。
三步操作:①多个哈希生成同key的多个hash值。
②多个哈希值对bit数组长度取模,得到哈希值在位图数组中对应位置。
③最后在对应位置设置1。
存在问题:
value会冲突,即布隆说存在并不一定存在。但查询不存在,则数据库一定不存在。
