缓存常出现的问题(缓存击穿、缓存穿透、缓存雪崩)

57 阅读4分钟

1.缓存穿透

定义: 缓存穿透是指需要访问的数据不存在于缓存中,那么直接会绕过缓存直接去访问数据库,而查询不到的数据不写入缓存中。如果说大量的数据(既不存在缓存中也不存在于数据库中)同时访问,这使得压力都给到数据库,引起数据库宕机。

解决方案:

  1. 设置特殊值:对于不存在的数据,设置一个特殊的值到缓存中。比如当数据库中查询到的值为空的时候,设置特殊值的到缓存中,下一次再访问的时候会直接查询缓存,然后直接返回这个特殊的值。坏处就是缓存中会存在大量无效数据,占用内存空间。
  2. 使用布隆过滤器做前置过滤:
  • 如果布隆过滤器认为值不存在,那么值一定不存在,就无需查询缓存或者数据库了。
  • 对于极低概率的误判,才会让非法数据访问缓存或数据库。

3.布隆过滤器做前置过滤 和 设置特殊值一起使用: 将布隆过滤器前置,按照方案2的方式过滤一波不会误判的数据,对于误判的数据再保存特殊值到缓存中,双重保险避免无效数据查询请求打到数据库上。

2.缓存击穿

定义: 某个热点数据突然失效,同时出现大量的请求,这些请求会直接打在数据库上,引起数据库宕机。

解决方案:

分布式锁

注意:在真实的业务场景下,并不一定要这么严格的使用双重检查分布式锁进行全局的并发限制。使用分布式锁虽然可以将数据库回源并发降低到最低,但也限制了缓存失效时的并发。可以考虑以下方法解决:

  • 使用进程内的锁进行限制,这样每一个节点都可以以一个并发回源数据库。
  • 不使用锁进行限制,使用Semaphore等类似的工具限制并发数,比如限制数设置为20。这样并发度高一些,数据库不至于压力很大。

缓存穿透和缓存击穿的区别?

  • 缓存穿透是指,缓存没有起到缓冲的作用(此时此刻的缓存形同虚设);
  • 缓存击穿是指,缓存数据失效时瞬时并发打到数据库上(瞬时失效)。

3.缓存雪崩

定义: 短时间突然缓存失效,这时高并发的访问到这些刚刚失效的数据,这些访问直接会访问数据库,对数据库造成极大的压力,甚至导致数据库宕机。

解决方案:

  1. 差异化缓存的过期时间,防止大量的缓存在同一时刻过期。比如,初始化缓存的时候,设置缓存的过期时间是“60s + 30s”以内的随机扰动(取0s-30s之间随机值)。这样大量的键值不会都集中在60s这个时刻同时过期,会分布在60s-90s之间。
  2. 让缓存不主动过期。初始化缓存的时候设置过期时间永不过期,然后启动一个后台线程每隔30s把所有的数据更新到缓存一次,并通过适当的休眠控制从数据库更新数据的频率,降低数据库压力。

注意:关于上面两种方案需要特别注意以下几点

  • 方法1和方法2是两种不同的方案,如果无法全量缓存所有数据,那么只能使用方法1。
  • 使用方法2,缓存永不过期,同样需要在查询时确保有回源的逻辑。因为无法保证缓存系统中的数据永不丢失。
  • 无论使用哪种方案,把数据从数据库加入到缓存中,都需要判断来自数据库的数据是否合法,例如进行最基本的判空检查。

缓存穿透与缓存雪崩的区别?

  • 缓存穿透是指并发的访问同一个数据(此时数据突然失效,通常这些数据是热点数据)。
  • 缓存雪崩是指并发访问不同数据(此时不同的数据突然都失效了)。