缓存可用性问题
高可用
缓存可用性问题
缓存击穿
缓存击穿:指(查询的数据)在缓存中无,DB中有
缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,导致大量并发请求打到数据库查询,在瞬间给数据库带来巨大的冲击。
缓存击穿的解决方案(解决缓存重建的这一段时间内产生并发问题):
- 互斥锁 -> 让这些并发的线程串行执行或者互相等待 -> 保证了一致性
- 逻辑过期 -> 访问得到的可能是旧数据 -> 保证了可用性
互斥锁:
- 思路:给缓存重建过程加锁,确保重建过程只有一个线程执行,其他线程等待
- 当查询key时,首先查询缓存,如果没有,需要先获取锁才能进入数据库查询,然后将查询结果保存到缓存,然后解锁。
- 如果发现查询锁被占用,则说明有线程正在获取。所以等待锁释放后可以直接访问缓存而不必进行数据库查询操作。
- 优点:
- 没有额外的内存消耗
- 保证一致性
- 实现简单
- 缺点:
- 线程需要等待,性能受影响
- 可能有死锁风险
逻辑过期:
- 思路:
- 热点key缓存永不过期,而是设置一个逻辑过期时间,查询到数据时通过对逻辑过期时间进行判断,来确定是否需要重建缓存
- 重建缓存也通过互斥锁保证单线程执行
- 重建缓存利用独立线程异步执行
- 其他线程无需等待,直接查询到旧数据即可
- 优点
- 线程无需等待,性能较好
- 缺点:
- 不保证一致性
- 有额外内存损耗
- 实现复杂
缓存穿透
缓存穿透:指(查询的数据)在缓存和DB中均无
缓存穿透产生的原因:用户请求的数据在缓存和数据库中都不存在,不断发起这样的请求,给数据库带来巨大压力
缓存穿透强调的是查询不存在的key,对于不存在的key 旁路缓存等设计模式,必然会打到DB查询,对于空key的查询将导致缓存失效
缓存穿透的解决方案:
- 缓存空值(空保护),并设置较短的过期时间
- 当查数据库返回的数据为空时,也设置缓存,例如缓存一个空对象或null值
- 通常TTL设置的较短,以保证一致性
- 优点:
- 实现简单
- 能有效防止同一不存在的 key 被重复攻击
- 缺点:
- 增加了一定的缓存成本,如果调用者大量查询空key,导致缓存过多空key,却将有效的key淘汰,则将造成系统命中率下降
- 在空值缓存的过期时间内,可能会存在短暂的数据不一致问题(比如刚缓存了空值,数据库里就创建了这条数据)
- 布隆过滤
- 布隆过滤器,bf假阳性对不存在的key判断是一定正确的,这说明bf可以有效防止空key查询,同时对空间的占用最小
- 接口层增加校验
- 如用户鉴权校验、做好数据的基础格式校验
- 请求来源限制
- 如IP白名单限制
- 增加id的复杂度,避免被猜测id规律
- 做好热点参数的限流
缓存雪崩
缓存雪崩:指缓存同时大量失效
原因:缓存中大量的key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
缓存雪崩的解决方案:
- 给不同Key的TTL添加随机值
- 在原有的ttl的基础上增加一个随机值,比如1-5分钟随机
- 利用Redis集群提高服务的可用性
- 给缓存业务添加降级限流策略
- 给业务添加多级缓存
This post is licensed under CC BY 4.0 by the author.