Redis 面试 —— 缓存雪崩、缓存击穿、缓存穿透

1、缓存雪崩

在给 key 设置过期时间的策略上没有限制,给一大堆的 key 设置了相同的过期时间,当达到过期时间的时,在某一刻有一堆的 key 都被清除了,这个时候,新来的请求全部去数据库请求,数据库瞬时访问压力过重而扛不住的情况。假如这个时候挂的是一个用户服务的数据库,这个时候所有依赖这个库的接口都会报错,就算重启,用户的请求依旧会把数据库搞挂,反复来个几次,用户也不玩了。

解决办法

最简单的解决方法就是把缓存失效的时间分散开来,例如可以在本来的失效时间上增加一个随机值,这样就不会有大量的 key 在同一时刻失效了。

2、缓存击穿

缓存击穿有点像缓存雪崩,但是又有些不一样,这种情况都是发生在设置了过期时间的 key,如果某个会过期的 key 在某个时间点可能被超高并发地访问,就有可能发生这个问题。假如恰巧在 key 过期的时候,又有大量对这个 Key 的并发请求过来,这个时候发现缓存过期,便会去数据库读取数据,同样因为请求量过大而搞挂数据库。

解决方法

1、可以设置热点数据永远不过期;例如 Redis 角度,不设置过期时间。

2、也可以加上互斥锁,在缓存失效的时候(判断拿出来的值为空),不立即去数据库读取数据,先使用带成功操作返回值的接口(比如 set 接口)获取一把锁,获取锁成功后,再去数据库读取数据,然后把读到的数据设置到缓存里,如果获取锁失败,就重新读 Redis 的缓存。

3、缓存穿透

当去 Redis 查询一个一定不存在的 key 时,因为缓存不会命中,就会去数据库读取,一般出于容错的考虑,在数据库查不到数据时,不会写入 Redis 中,而这种查询不存在的 key 时,每次请求都会跑去数据库查询,Redis 这层缓存就失去了意义。在流量大的时候,或者有人恶意使用不存在的 key 去查询的时候,就会把数据库搞挂。

解决方法

我记得华为学习手册里面有这样一种定义 —— 可信域、不可信域。对外提供的接口,因为调用方不是自己的程序,不能确定调用者会为这个接口传递什么参数,所以传递的参数是不可信。大体是这样描述,细节记不清楚了,基于这一条,加强对参数的校验,从而屏蔽这种不可信可能造成的潜在危机。

上述的方法只是降低了缓存穿透的概率,并不能完全解决,所以还需要有一定的补充。当从 Redis 中取不到数据,且数据库中也没有数据,这时把这个 key 的 value 写为 null 或者什么(根据具体情况而定),同时把缓存超时时间设置的短一点,避免由于设置过长导致的正常情况也没法使用。

一般情况下,正常用户,不会有意频繁去尝试无效 key 的请求,所以,可以让运维人员设置每个 IP 每秒可以访问次数的限制。

发布了34 篇原创文章 · 获赞 34 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_19154605/article/details/104302302