解决缓存击穿
解决缓存击穿拾很容易的,只需要用到我们在缓存模式里面提到的singleflight模式。也就是说,就算是一个热点数据,当几百个请求缓存未命中的时候,在singleflight模式下,也只有一个请求会真的去查询数据,剩下的都在等着这个请求查询回来的结果。
解决缓存雪崩
缓存雪崩也很容易解决,之所以有雪崩,就是因为一次性加载了一大批数据放到了这个缓存里面,并且设置了同样的过期时间。
那么解决思路自然就有两个,一个是不允许一次性加载一大批数据到缓存,而这显然不现实,因为批量加载属于业务要求;另外一个思路就是设置不同的过期时间。
最简单的思路就是在过期时间的基础上增加一个偏移量。
要解决缓存雪崩,就是在数据批量加载到缓存的场景中在过期时间的基础上加一个随机量。比如,我预计这一批数据的过期时间是15分钟。那么我就在设置每一条数据的过期时间的时候,在15分钟的基础上加一个0~180秒的偏移量。那么这一批数据就不会在同一时刻过期,也就不存在缓存雪崩的问题了。
这时候,面试官可能会问你这个偏移量的范围怎么确定。比如说在你的回答里面,你说的是 0~180 秒的偏移量,那么 0~10 秒的偏移量行不行?这时候你要抓住核心,偏移量要跟过期时间成正比,不能过低或者过高。
这个随机偏移量应该和过期时间成正比。比如说如果过期时间是15分钟,那么随机偏移量在0~180秒都可以。如果数据量不多,那么0~60秒也可以。而如果过期时间很长,比如4个小时,也可以把偏移量控制在0~10分钟。如果过期时间很短,比如只有10秒,这个偏移量就需要控制在0~3秒内了。
当然,偏移量这个东西,除了随机生成,也可以有别的算法。比如说第一条数据加上 1 秒偏移量,第二条数据加上 2 秒,以此类推。
限流
引发缓存穿透、击穿和雪崩等问题的一个关键是有很多请求落到了数据库上。一个最简单的方法就是限制住这些请求,不让他们落到数据库上,限流就可以用在这些场景。
你可以问答限流的基本思路。
缓存穿透和击穿只有在高并发下才会成为一个问题,所以一个很自然的想法就是使用限流。限流可以考虑在两个地方用:服务层面和数据库层面。
在服务层面上限流,是有一个隐含假设的,可以强调一下这个假设,就是数据库撑得住。
在服务层面上限流的时候,要保证只要QPS没有超过这个数值,就算所有的请求都命中缓存,直接落到了数据库上,数据库也能撑得住这个流量,但是有些时候也难以保证。或者说大多数人在考虑限流阈值,包括使用压测来确定限流阈值的时候,都已经把命中缓存这种情况考虑进去了。所以需要进一步考虑数据库层面上的限流了。
为了防止数据库崩溃,最好在数据库访问上加一些限流措施。显然,就算数据库没有崩溃,这个限流还是可以保护数据库免遭大流量的冲击。
数据库层面上的限流总的来说是必不可少的。不管是缓存崩溃,还是穿透或者击穿,限流都能保护住数据库。如果使用了数据库代理,并且这些代理支持限流,那么就可以直接在代理上做限流。如果没有使用代理或者代理不支持,那么就可以考虑在 ORM 上做。
#