这篇分享缓存异常场景和缓存一致性... 这两个相关性高,容易左脚踩右脚螺旋升天...
缓存异常三连
缓存穿透(缓存、数据库双杀)
缓存穿透是什么
查一个 缓存和数据库都没有的数据就是穿透
高频请求直接打数据库会把数据库打崩
为异常数据建立数据项并重建缓存,比如给异常数据设置数据库记录项“nil”...(兜底)
怎么办
作请求合法校验,异常数据直接不让查,比如设计的ID 范围是 0 - 65535 uint16 的值但是查询的ID 是-1,这种直接丢
缓存后面架个布隆过滤,没有一定没有(然后返回),但有的数据只是可能有(布隆过滤是几个哈希函数映射一个bit位表,其他数据可能会提前占用这个数据刚好对应的几个比特位)。
一般联合使用.
缓存击穿 (没有缓存,数据库有)
缓存击穿是什么
缓存没有,但数据库有
如果不及时缓存重建,高频请求会打崩数据库
怎么办
每次查询就刷新,续期
及时重建缓存,发现缓存失效业务线程加分布式锁拉数据重建缓存,其他线程发现有锁后休眠等待或者返回。
某证券方案,多重缓存
缓存雪崩
缓存雪崩是什么
大量key在同一时间失效,导致大量查询直接打向数据导致数据库负载过大崩溃。
怎么办
每次查询就刷新,续期
设置随机EX/PEX,防止同一事件批量过期
设置二级缓存,二级缓存过期时间是一级缓存时间过期时间更长。
及时加分布式锁重建缓存,竞争线程发现已加锁直接返回,或者短时休眠等待
简谈一致性
缓存一致性如何保障
大致方向有三:
只更新后端数据库,设置缓存过期不管缓存,等缓存过期后再重建(完全以过期时间兜底)
更新后端数据库后,再操作Redis
异步将后端数据库(MySQL)更新同步给Redis: 比如先更新MySQL,Redis 作为MySQL 从机用阿里开源的canal组件 订阅MySQL binlog 异步更新Redis
分析
方向1:
缺点:
完全依赖过期,每次数据库更新都会产生脏数据
设置过期时间太短会频繁失效,过长会容易有较长时间不一致,开发者编程和场景经验有一定经验
优点:
管理成本低,出问题概率小
redis 原生接口,开发成本低,易实现
方向2:
缺点:
后端数据库更新后需要操作redis 需要消耗资源
若是数据库更新后也更新redis,容易出现时序问题,由于网络延时导致的延时问题不可避免
删除失败后会退化成方向1,但可以使用双删尝试解决
优点:
对比方向1 达成一致的滞后时间缩短
开发成本低,若为删除缓存,只需要添加删除逻辑。
方向3:
缺点:
引入消息队列这种重型组件,需要搭建同步服务,维护成本不低
同步服可能会成为系统关键节点,同步服务崩了,缓存得不到及时更新
异步更新码,可能达成一致的时间会较长,适合长时间不怎更新的业务,或者不怎需要即时更新的业务,比如电影网站,稍晚点入库几部电影也没问题。
优点:
与开发解耦更新MySQL 时不需要再额外操作缓存
无时序性问题,可靠性强