redis缓存设计及常用问题
缓存的收益与成本分析 缓存更新策略的选择以及使用场景 缓存粒度控制法 穿透问题优化 无底洞问题优化 雪崩问题优化 热点key重建优化 收益与成本
收益
-
加速读写
-
降低后端负载 成本
-
数据不一致性
-
代码维护成本
-
运维成本 缓存更新策略
-
lru,ttl,random,allkey-lru,allkey-random,no-enviction(内存达到最大值时的缓存策略) 2.超时删除 (设定过期时间) 3.主动更新(用于数据一致性较高) 缓存粒度
-
全部数据缓存以及部分数据缓存的选择
-
思考缓存粒度从几个维度考虑: 数据通用性,空间占用比,代码维护性 通常缓存全部数据 通用性好,代码维护简单,但是空间占用大,而缓存部分数据则相反 穿透问题
原因:cache miss 后直接请求后端服务,常发生在业务代码异常,或者大量恶意攻击导致的
解决方法:
- 空对象缓存,但是需要注意缓存空间的使用情况,对空对象缓存时间尽量要小
- 布隆过滤器缓存 miss cache 直接返回 不请求后端服务,但是必须有定时程序往缓存中写数据,适用于数据缓存命中不高的场景 布隆过滤器
用途:快速查询一个元素是否在一个集合中
入参:失败率,集合个数
原理:用k个hash函数将结果存在一个位数组中,检查的时候对比每一个位上是否是1 如果全是的话 则说明命中
说明:结果在,有可能不在 结果不在,则一定不在 无底洞问题
表现:集群增加节点依然性能不佳。耗时有可能还有增加
原因:客户端使用mget之类批量获取key的命令时候,会导致更多的io请求。在redis cluster中 key是分布在各个slot中,批量操作的话会增加更多的网络io
解决方式:
-
相同节点key 合并。总时间 = node + n次命令时间
-
redis 强制将这些key 写入同一个slot中
性能比较
- 编程复杂,需要考虑多线程开发的问题
- 性能最高,维护成本很高,但是容易发生数据倾斜的问题 雪崩问题
表现:在缓存层中服务不可使用,导致后端服务负载过高,出现宕机的情况
解决办法:
- 缓存高可用架构 (master/slaver,哨兵,cluster)
- 后端限流降级 (限流3个手段 计数器,漏斗,令牌桶)
- 提前对业务进行故障演练,正确估计缓存性能,负载情况 热点key重建
表现:通常 缓存key+过期时间,能保证绝大部分需求,但是有2种情况下,这样的做法会引起性能问题
- 热点key 过期重建
- 重建的逻辑计算相当复杂
原因。热点key中 会有大量的线程尝试重建缓存,导致后端负载过大,甚至引起宕机 解决方式:
- 引入分布式锁 保证同一时间只有一个请求来进行key 重建
- 设定key 永不过期 直到他变成不是热点key