Redis(十四)——缓存问题
1、缓存穿透
(1)问题描述
缓存和数据库中都没有数据。例如利用不存在的key恶意攻击,导致数据库压力过大
(2)解决方案
- 接口层增加参数校验,用户鉴权,id非法拦截。
- 从缓存取不到数据,数据库也没有查到,返回值在缓存设置短时间默认值或者空。
- 布隆过滤器快速判断key是否存在数据库。
2、缓存击穿
(1)问题描述
1个key过期时,访问量巨大
(2)解决方案
- 热点数据永不过期
- 互斥锁,第一个线程访问key的时候就锁住,等查询数据库返回后,把值写到缓存再释放锁,后续请求直接取缓存。
3、缓存雪崩
(1)问题描述
大量key同时过期或者缓存服务器宕机也算雪崩
(2)解决方案
- 热点数据永不过期
- 缓存数据的过期时间设置随机
- 分布式缓存集群,确保高可用,例如redis-cluster
4、缓存和数据库一致性
(1)问题描述
数据库与缓存更新,可能会出现数据不一致的情况。写和读是并发的,无论是「先写数据库再删缓存」还是「先删缓存再写数据库」都可能出现数据不一致的情况。
- 如果删除了缓存Redis,还没有来得及写库MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据。
- 如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。
(2)解决方案
- 先删缓存再写数据库:一般情况用这个就够了。这种操作出现数据不一致的条件是:读缓存时缓存失效,而且并发着有一个写操作,读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存。 但实际上写操作会比读操作慢很多,还要锁表,因此满足数据不一致的概率不大。
- 队列+失败重试:写库成功后删除缓存失败,将key发到MQ中消费,失败继续发MQ,直到成功。缺点是对业务代码造成大量入侵。
- 订阅binlog:订阅MySQL的写操作日志,更新redis。