在项目中,通常会使用数据库比如 MySQL 存储应用数据,但是当数据太多之后,比如多了几十万条或上百万条的商品信息,这个时候查询商品数据的速度会很慢,影响用户体验。此时一般我们会选择将部分商品信息缓存起来,提高商品的查询速度,比如使用 Redis 将明天参加秒杀活动的商品提前缓存起来,用户直接访问到缓存。速度不会很慢,也不会对数据库产生太大压力。
不过,Redis 缓存也会出现问题,最常见的 缓存雪崩、缓存穿透、缓存击穿。
缓存雪崩
在某个时间点,缓存出现的大量失效的情况,导致大量的数据直接请求到了数据库,就像雪崩一样,给数据库造成巨大压力。或者 Redis 突发故障,请求直接到了数据库,同样会造成数据库压力激增,甚至直接崩溃。比如夏天到了,很多人在电商软件上挑选短袖等,需要频繁访问,频繁查询商品的信息。假如突然缓存失效了,大量查询的请求直接请求到了后端数据库,造成了缓存雪崩。数据库承受不住这么大的压力崩溃了,那么用户就不能再进行挑选商品。
解决方案
针对大量同时过期
1. 设置不同的,或者随机的过期时间,避免出现同时过期的情况。
2. 多级缓存。比如本地缓存和分布式缓存相结合,减少单点故障风险。
3. 缓存预热。系统提交将数据预热到缓存中。
4. 加锁。保证只能一个请求能访问到数据库,等到该请求同时在缓存中创建数据之后,其他请求直接访问到缓存。
5. 接口限流,避免同时处理大量请求。
针对中间件故障可以使用集群。
缓存击穿
针对某一热点数据在一个时间点在处理大量请求时突然失效,导致直接请求到数据库。比如说某款热点电子产品需要到点秒杀,此时缓存失效了,大量秒杀请求打在数据库上,导致压力激增。
和缓存雪崩的区别,缓存击穿针对的是某个热点 key,缓存雪崩针对的是多个 key。
解决方案
1. 缓存失效时间。热点缓存可以设置超过活动期间的时间,或者直接不设置过期时间,避免活动中途出现缓存实现。
2. 加锁。和缓存雪崩一样,如果已经出现了大量请求访问到后端时,通过加上互斥锁,确保只有一个请求能访问到数据库,然后其他请求等待这个请求将数据构建到缓存之后直接从缓存提取。
缓存穿透
针对缓存和数据库中不存在的数据。因为缓存不存在,每次请求都是直接访问数据库,导致数据库负载增加。会有攻击者通过构造不存在的key发起大量请求,造成系统崩溃。
解决方法
1. 无论什么情况,提前做好参数检验比如 主键 id<0直接返回错误,身份证号码位数不对直接返回错误等。
2. 接口限流。避免同时处理大量请求,并且可以设置黑名单,对频繁请求的账号做黑名单处理。
3. 缓存空值。将没有查询到的数据缓存一个空值返回给客户端,下次直接访问空值缓存。
4. 布隆过滤器。