缓存

简介

简而言之,即是数据存储的缓冲区。使用缓存之后,可以减轻访问数据库的压力,显著的提升系统的性能。

使用缓存的一般流程如下:

use_cache

缓存通常有两种:

  • 服务器主集本身的内存缓存,也就是我们说的二级缓存。
    • 相比于缓存中间件性能更好。但只能应用于本机,若系统分布式部署,会存在数据不一致的问题。
  • 缓存中间件,比如:Redis、Memcached等
    • 适用于分布式缓存,解决分布式数据一致性问题

有些业务场景,分布式缓存和二级缓存可以一起使用

缓存带来的问题

1. 缓存雪崩

缓存雪崩指的是当某一个时间段出现大规模的缓存失效的情况,此时大量的并发请求直接命中在数据库上面,导致数据库压力巨大,甚至宕机。

分析

造成缓存雪崩的关键在于在同一时间段大量的key失效。出现这个问题的可能性:1. 缓存宕机。2. 采用了相同的过期时间。

解决方式

  1. 过期时间采用随机值
  2. 若真的发生了缓存雪崩,使用熔断机制。当流量到达一定阈值,直接返回“系统拥挤”之类的提示,防止过多的请求打在数据库上。至少能保证一部分用户是可以正常使用,其他用户多刷新几次也能得到结果。
  3. 提高数据库的容灾能力,可以使用分库分表,读写分离的策略。
  4. 防止Redis缓存宕机导致缓存雪崩的问题,可以搭建Redis集群,提高Redis的容灾性。

cache collapse

2. 缓存击穿

缓存击穿指的是大量并发集中访问某一个 key,突然这个 Key 缓存失效了,导致大并发一时间全部命中在数据库上。

与缓存雪崩对比

  • 缓存雪崩是大量的 key 失效导致的
  • 而缓存击穿是大规模访问一个失效的 key 导致的

分析

关键在于某个热点 key 失效了,导致大并发集中打在数据库上。

所以要从两个方面解决,第一是否可以考虑热点key不设置过期时间,第二是否可以考虑降低打在数据库上的请求数量。

解决方式

  1. 若业务允许,对热点 key 可以设置永不过期
  2. 使用互斥锁。当缓存失效时,只有拿到锁才可以查询数据库,降低了在同一时刻命中在数据库上的请求。
    1. 可以对 Key 进行加锁
    2. 相应的,加锁会导致系统性能降低。

3. 缓存穿透

假如请求的 key 是在缓存中是不存在的,那缓存查不到就会去数据库查询。如果有大量这样的请求,这些请求像“穿透”了缓存一样直接命中在数据库上,这种现象就叫做缓存穿透。

分析

关键点是缓存中查不到 Key,这些 key 是不存在的

PS:说明了边界安全的重要性。应该做好参数检验,外界不可信

解决方式

  1. 把无效的Key存入缓存。如果缓存查不到,数据库也查不到,可以把这个 Key 值存入缓存,并设置value=“null”,当下次再通过这个Key 查询时就不需要再查询数据库。

    1. 弊端是,假如传进来的这个不存在的Key值每次都是随机的,那这种做法无意义。
  2. 使用布隆过滤器。布隆过滤器的作用是某个 key 不存在,那么就一定不存在,它说某个 key 存在,那么很大可能是存在(存在一定的误判率)。因此,可以在缓存之前再加一层布隆过滤器,在查询的时候先去布隆过滤器查询 key 是否存在,如果不存在就直接返回。

    1. 参考:https://cloud.tencent.com/developer/article/1687510