一、缓存穿透(数据库没有,缓存没有)

1、概念

当查询Redis中没有数据时,该查询会下沉到数据库层,同时数据库层也没有该数据,当出现大量这种查询(或被恶意攻击)时,接口的访问全部透过Redis访问数据库,而数据库中也没有这些数据,我们称这种现象为“缓存穿透”。

缓存穿透会穿透Redis的保护,让底层数据库的负载压力变大,同时这类穿透查询没有数据返回也造成了网络和计算资源的浪费。

2、解决方案

  • 在业务服务访问层对请求进行校验,比如:请求参数、登录状态、N秒内访问接口的次数、随机数、时间戳等。判断是不是来自恶意用户的请求,可避免进一步访问缓存和数据库。
  • 对于查询为空的数据,可以将这个空结果(或者设置一个默认值)进行Redis缓存(将key-value对写为key-null或者key-default),这样后续请求就可以从缓存中读取到空值或者默认值返回给应用,而不会继续查询数据库。但是需设置很短的过期时间,比如30s(设置太长可能会导致正常情况也无法使用),也可根据实际业务需求设定。注意一定不要影响正常的业务。
  • 利用布隆过滤器将数据库层有关数据的键存储到布隆过滤器中,以判断访问的键是否在底层的数据库中。如果在布隆过滤器中则查询缓存,如果缓存没有则再次查询数据库;如果布隆过滤器中没有,则直接返回预先规定的结果即可。

因为哈希冲突的存在,布隆过滤器有误判率,查询布隆过滤器说数据存在,并不一定证明数据库中存在这个数据,但是查询到数据不存在,数据库中一定就不存在这个数据。

虽然布隆过滤器不能完全避免数据穿透的现象,但已经可以将99.99%的穿透查询屏蔽在Redis层,极大的降低了底层数据库的压力,减少了资源浪费。

二、缓存击穿(数据库有,缓存没有)

1、概念

当某个热点数据(被频繁访问的数据)的键从缓存中淘汰出去后,大量访问同时请求这个数据就会将查询下沉到数据库层,此时数据库层的负载压力增大,我们称这种现象为“缓存击穿”。

2、解决方案

  • 不给热点数据设置过期时间,由后台异步更新缓存。或者在热点数据准备要过期前,提前通知后台线程(或者是定时任务)去更新缓存以及重新设置过期时间。
  • 利用互斥锁保证同一时刻只有一个客户端可以查询底层数据库的数据。在根据key获取value值为空时,先锁上,然后从数据库加载,一旦查到数据就缓存至Redis内,然后释放锁。若其他线程也在请求该key时发现获取锁失败,则休眠一段时间(比如100ms)后再重试,以避免其他大量请求同时穿过Redis去访问底层数据库。

三、缓存雪崩

1、概念

Redis中大量的键几乎同时过期或者Redis发生故障宕机,大量并发的查询穿过Redis冲击到底层数据库上,此时数据库层的负载压力会增大,我们称这种现象为“缓存雪崩”。

2、解决方案

  • 在可接受的时间范围内随机设置键的过期时间,分散键的过期时间,以防止大量的键在同一时刻过期
  • 使用多级缓存机制
  • 对于一定要在固定时间让key失效的场景(例如每日12点准时更新所有最新排名),可以在固定的失效时间时在接口服务端设置随机延时,将请求的时间打散,让一部分查询先将数据缓存起来;

-------------------------------本篇文章到此结束-------------------------------------