缓存穿透、击穿、雪崩等问题及方案

缓存问题总结

前言

通常应用中会使用数据库来作为数据存储,但是数据库面向磁盘,磁盘的读写速度比较慢,不合适处理高并发的应用场景,为了避免高并发场景下瞬间大量访问DB导致数据库系统瘫痪的问题,我们通常会使用缓存来提高系统支持高并发的能力。缓存一般都是基于内存的数据库,读写效率相比于磁盘读写都有大幅提升,但引入缓存后相应也会引入一些缓存相关的问题。

缓存问题

  • 缓存穿透
  • 缓存击穿
  • 缓存血崩
  • 缓存溢出
  • 数据丢失

下面我们以redis为例,来分析这些问题并给出对应的解决方案。

问题分析

缓存穿透

缓存穿透指的是数据源(通常是DB)中,没有key对应的数据源,因此请求这类不存在的key,在缓存中获取不到的话就需要直接请求数据源,请求并发量大的话就会给数据源造成压力和风险。

针对这类问题,有两个常用的解决方案:

1.即使查询数据源没有该key对应的值,也在缓存中缓存该key,并设置空的value值。需要注意的是,必须给这种key设置一个短的过期时间,在这段时间内数据源新增了这个key对应的记录但是获取不到的情况。由此可见,该方案存在一个问题就是新增的记录可能存在不能立即生效的问题。

2.第二种方案是使用布隆过滤器,将可能的key值数据取哈希存储到一个bitmap中,通过判断key值是否在bitmap内来避免向数据源请求不存在的记录。

缓存击穿

缓存击穿和缓存穿透不同,缓存穿透是请求不存在key记录,而缓存击穿请求的key在数据源中是有对应的记录的。对于热点数据的key,如果刚好在缓存过期的时间后有大量并发请求,就会给数据源造成服务崩溃风险。

针对这一问题,通常的方案是加互斥锁,只有获取锁的线程可以请求数据源,其他请求可以等待重试获取缓存。

对于redis来说,可以通过SETNX操作来设置一个互斥key来实现互斥锁,设置成功则代表成功获取锁。需要注意的是需要给互斥key来设置一个过期时间,避免死锁问题。

此外,也可以设置热点数据不过期来解决这类问题。

缓存雪崩

缓存击穿是针对某一个key过期时的并发问题,而缓存雪崩是缓存服务器重启或者大量缓存集中在一个时间段过期,导致大量并发请求直接打到数据源,造成数据源服务崩溃。

缓存雪崩的几个解决方案:

  1. 采用随机的过期时间。可以在设置缓存过期时间时,尽量分散各个key的过期时间避免集中过期的场景
  2. 使用锁或者队列。通过锁或者队列来避免所有请求直接请求数据库。这种会导致线程阻塞,可能影响用户体验。
  3. 缓存标记。通过记录缓存数据是否过期,如果过期则通知专门的线程来处理实际key的更新。

缓存溢出

缓存使用的是内存资源,相比于磁盘存储来说可以缓存的数据有限的。缓存溢出是指缓存的数据达到上限,无法缓存更多的数据。

这种问题的解决方案通常是给缓存设置一定的淘汰策略,一般使用LRU(Least Recently Used)。最近最少使用的key会被优先淘汰。

数据丢失

缓存数据在内存中,如果缓存服务器宕机或者重启,内存中的数据就会丢失。

针对这一问题,主要依赖于缓存服务的持久化。redis提供了两种数据持久化的方案,一种是RDB,一种是AOF。

RDB是在指定的时间间隔内生成数据集的时间点快照,是一个非常紧凑的文件,适用于灾难恢复,同时数据备份时只需要分配一个子进程来处理数据保存工作,父进程无需执行磁盘IO操作,可以最大化Redis的性能。

AOF的话可以让Redis非常耐久,尽可能短的减少数据丢失问题。但是备份文件体积要大于RDB,性能及恢复效率上不如RDB。

转载请注明出处,如有错误的地方请留言给我更正,谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值