缓存设计问题

概述

缓存设计需要关注的点

  • 关注指标:
    • KV大小
    • 读写峰值
    • 命中率
    • 缓存空间大小
    • 置换策略
    • 穿透加载时间
  • 分类
    • 本地缓存
    • 远程缓存
  • 应用模式
    • Cache Aside
    • Read/Write Through
    • Write Back Caching
  • 技巧/Tips
    • 不要把缓存当数据库使用
    • 评估业务所需缓存空间大小
    • 缓存会给系统带来数据不一致的风险
    • 尽量设置过期时间
    • 缓存对象太大需要考虑做压缩,减少存储空间以及传输中带宽的占用
    • 引入多级缓存时,需要考虑数据一致性
    • 提前考虑扩容问题

常见的缓存问题

缓存雪崩

很多使用场景,查询的缓存数据都是由定时任务取刷新,然后缓存查不到从 DB 查了在更新缓存。如果这些 key 在同一时间失效, 那么失效的时候,大量的请求过来。就会直接打到 DB 上, 这个时候 DB 很可能被打垮,即使马上重启也会被新的流量打垮。

这种同一时间大量缓存的失效,导致请求直接打到 DB 上的情况, 就是缓存雪崩。

针对于这种情况,在批量写 Redis 数据的时候, 从缓存的过期时间入口,将原来的固定过期时间,调整为过期时间=基础时间+随机时间,让缓存慢慢过期,避免瞬间全部过期,对DB产生过大压力。

缓存穿透

缓存穿透指的是缓存缓存和数据库中都没有的数据,而用户不断发起请求,让请求直接落再DB上,增加数据库压力,可能导致数据库被击垮。这种请求很可能是攻击者恶意发起的。

针对这种情况首先要做好数据校验,不合法的数据尽量拦截掉.

  • 其次如果缓存差不到,数据库也查不到的数据也缓存起来。将 value 存个null, 过期时间短一点(如30s,如果设置太长肯恶搞导致正常的情况数据没法及时更新)。
  • 另外还可以使用 Redis 提供的布隆过滤器,可以高效的判断出某个key是否在数据库当中,如果通过布隆过滤器判断出不存在,直接返回,存在了在去DB取数据刷新缓存。

缓存击穿

在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。

针对这种情况可以:

  • 异步设置热点key过期时间, 提前续上
  • 缓存失效的时候, 加上一个全局的锁再去load db, 避免所有线程都打到db上

hot key 问题

对于某些 key 有非常大的访问量, 容易把 hot key 所在的那台机器打垮。

解决方案:

  • 冗余 hot key: 一个缓存节点过载。由于只有一个key,我们可以在key的后面拼上有序编号,比如key#01、key#02。。。key#10多个副本,这些加工后的key位于多个缓存节点上。 每次请求时,客户端随机访问一个即可

big key 问题

当访问缓存时,如果key对应的value过大,读写、加载很容易超时,容易引发网络拥堵。另外缓存的字段较多时,每个字段的变更都会引发缓存数据的变更,频繁的读写,导致慢查询。如果大key过期被缓存淘汰失效,预热数据要花费较多的时间,也会导致慢查询。

解决方案:

  • 方案一:设置一个阈值,当value的长度超过阈值时,对内容启动压缩,降低kv的大小
  • 方案二:颗粒划分,将大key拆分为多个小key,独立维护,成本会降低不少
  • 方案三:大key要设置合理的过期时间,尽量不淘汰那些大key

缓存一致性问题

在另一篇博客有详细的介绍: MySQL与缓存一致性问题

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=308w50b8ve0wo


缓存设计问题
https://haobin.work/2022/02/14/架构源码/缓存设计问题/
作者
Leo Hao
发布于
2022年2月14日
许可协议