缓存设计问题
概述
缓存设计需要关注的点
- 关注指标:
- 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