[{"createTime":1735734952000,"id":1,"img":"hwy_ms_500_252.jpeg","link":"https://activity.huaweicloud.com/cps.html?fromacct=261f35b6-af54-4511-a2ca-910fa15905d1&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=201905","name":"华为云秒杀","status":9,"txt":"华为云38元秒杀","type":1,"updateTime":1735747411000,"userId":3},{"createTime":1736173885000,"id":2,"img":"txy_480_300.png","link":"https://cloud.tencent.com/act/cps/redirect?redirect=1077&cps_key=edb15096bfff75effaaa8c8bb66138bd&from=console","name":"腾讯云秒杀","status":9,"txt":"腾讯云限量秒杀","type":1,"updateTime":1736173885000,"userId":3},{"createTime":1736177492000,"id":3,"img":"aly_251_140.png","link":"https://www.aliyun.com/minisite/goods?userCode=pwp8kmv3","memo":"","name":"阿里云","status":9,"txt":"阿里云2折起","type":1,"updateTime":1736177492000,"userId":3},{"createTime":1735660800000,"id":4,"img":"vultr_560_300.png","link":"https://www.vultr.com/?ref=9603742-8H","name":"Vultr","status":9,"txt":"Vultr送$100","type":1,"updateTime":1735660800000,"userId":3},{"createTime":1735660800000,"id":5,"img":"jdy_663_320.jpg","link":"https://3.cn/2ay1-e5t","name":"京东云","status":9,"txt":"京东云特惠专区","type":1,"updateTime":1735660800000,"userId":3},{"createTime":1735660800000,"id":6,"img":"new_ads.png","link":"https://www.iodraw.com/ads","name":"发布广告","status":9,"txt":"发布广告","type":1,"updateTime":1735660800000,"userId":3},{"createTime":1735660800000,"id":7,"img":"yun_910_50.png","link":"https://activity.huaweicloud.com/discount_area_v5/index.html?fromacct=261f35b6-af54-4511-a2ca-910fa15905d1&utm_source=aXhpYW95YW5nOA===&utm_medium=cps&utm_campaign=201905","name":"底部","status":9,"txt":"高性能云服务器2折起","type":2,"updateTime":1735660800000,"userId":3}]
缓存是一种提高系统性能的一种常见手段,其中 Redis
是一种常用的高性能缓存数据库。但是在使用缓存时,可能会遇到一些问题,比如缓存雪崩、缓存击穿、缓存穿透等问题。
缓存雪崩
缓存雪崩是指大量的缓存数据几乎在同一时间内失效,而这时候又刚好碰上大量请求过来获取该数据, 导致缓存没有击中,所有的请求都直接打在了我们的后端数据库中;
在 Redis 作缓存的场景中,表现的原因有:
* 大量的 key 几乎在同一时间失效
* Redis 宕机,导致所有 key 不可用
解决方案
针对第一个原因,我们可以采取以下的策略进行预防:
* 均匀地设置过期时间,避免大量数据同时失效(过期时间 Random 化)
* 使用互斥锁构建缓存,避免所有请求都打到后端数据库
* 采用双 key 策略,主 key 设置过期时间,备 key 不设置,在主 key 失效的时候,可以返回备 key;也可以采用逻辑过期的策略,比双
key 更加节约内存空间,缺点是实现难度比双 key 大一些。
* Redis 后台构建缓存,可以是定期巡检,发现过期了就触发构建缓存,也可以是业务线程发现缓存失效后,通知 Redis 后台线程构建缓存。
针对 Redis 宕机的原因,我们可以这么做:
* 合理设计服务熔断或者请求限流机制,避免大量请求同时打到数据库。
* 构建 Redis 高可用集群,避免 Redis 缓存层面的不可用。
可以看到我们解决缓存雪崩的核心点就是避免大量请求同时打到后端数据库,造成数据库压力骤增,从而避免了雪崩情况的发生。
缓存击穿(热点 key)和缓存雪崩很像,它是指一个或者几个缓存数据失效,大量请求过来获取该数据,
导致缓存没有击中,所有的请求都直接打在了我们的后端数据库中;
缓存击穿可以看成是缓存雪崩的一个特例, 因为缓存击穿更多的是热点数据失效导致的,而不是大量数据;
所以我们也是可以用互斥锁、设置逻辑过期和后台构建缓存的方案来解决缓存击穿
缓存穿透,和前面两种不同,
前面两种只是缓存没击中,还是有数据库兜底的;但是缓存穿透就不一样了,它是缓存没有该数据,数据库也没有该数据的。在数据库里也查不到数据。
缓存穿透产生的情况一般是:非法请求,专门请求数据库没有的数据
解决方案:
* 限制非法请求
* 缓存空值或者默认值
* 使用布隆过滤器提前发现数据库中是否存在该数据
可以看到解决这类问题的核心是在该类场景下,避免大量请求到达数据库, 在达到这个目的的前提下,可以有多种解决方案。
这里的根本原因是数据库所能承受的并发量不是特别高所决定的。