Redis 缓存设计 - 缓存穿透/雪崩/击穿

缓存收益和成本

  1. 缓存收益
  • 加速读写
  • 减低后端负载
  1. 缓存成本
  • 数据不一致问题:缓冲层和数据层保存的数据可能不一致
  • 代码维护成本变高,多了一层缓存逻辑
  • 运维成本,例如 Redis cluster的维护
  1. 使用场景
  • 减低后端负载:对高消耗的SQL结果进行缓存,例如join结果集/分组统计结果
  • 加速请求响应
  • 大量写合并为批量写,如计数器先Redis累加再批量写到DB

缓存更新策略

  1. LRU(Least Recently Used),根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高,则延迟其淘汰时间” - LRU缓存更新
  2. LFU(Least Frequently Used)根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”- LFU缓存更新
  3. FIFO ,根据"先进先出" 思想来更新缓存数据
  4. 超时剔除 - expire
  5. 主动更新 - 开发控制生命周期
  6. 扩展:缓存污染 - 缓存污染降低了缓存的使用率,把不常用的数据读取到缓存,同时会把常用的数据移出缓存,这样会直接降低系统的数据命中率

缓存穿透问题

  1. 定义:缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次无用的查询),导致大量请求发到了数据库上。
    缓存穿透.png
  2. 解决方法

  • 缓存空对象:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短,不超过5分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库。
    存在的问题:
    (1)需要更多的键,所以通常设置较短过期时间
    (2)缓存层和存储层数据"短期"不一致

    设置NULL.jpg

  • 布隆过滤器拦截:

    对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。例如Redis可以使用bitMap来实现布隆过滤器
    布隆过滤器.jpg

缓存雪崩问题

  1. 定义:缓存雪崩是指,由于缓存层承载着大量请求,有效的保护了存储层,但是如果缓存层由于某些原因整体不能提供服务(可能是机器宕机或大量的缓存(key)在同一时间失效 - 过期),于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
  2. 解决方法
  • 保证缓存层服务高可用性:即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务,比如 Redis Sentinel 和 Redis Cluster 都实现了高可用。
  • 依赖隔离组件为后端限流并降级:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 数据预热:可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀

缓存击穿问题

  1. 定义:一个存在的热点key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到数据库,造成瞬时数据库请求量大压力骤增。
  2. 解决方法
  • 互斥锁
  • 永不过期

参考资料

[1] https://coding.imooc.com/class/151.html
[2] https://www.cnblogs.com/George1994/p/10668889.html
[3] https://www.jianshu.com/p/b57d0773ee96
[4] https://blog.csdn.net/zeb_perfect/article/details/54135506

你可能感兴趣的:(Redis 缓存设计 - 缓存穿透/雪崩/击穿)