缓存能够有效的加速应用的读写速度,同时降低后端负载,不过将缓存加入架构后也可能引入一些新的问题。这里我们对常见的问题进行汇总与解决
缓存穿透
指查询一个根本不存在的数据,缓存层和存储层都不会命中,通常出于容错的考虑,如果整个存储层查不到数据则不写入缓存层。导致每次请求都要到存储层去查询,失去了保护后端存储的意义。
原因:
自身业务代码或者数据出现问题
一些恶意攻击,爬虫等造成
解决办法:
缓存空对象,并设置过期时间。如果存储层添加对应数据时,利用消息系统或者其他方式清除缓存
布隆过滤器,在缓存层和存储层之间,用布隆过滤器保存起来,做一层拦截。适用于数据命中不高,数据相对固定的应用。
缓存雪崩
当由于某种原因,缓存层不能提供服务的时候,所有请求都会到达存储层,造成存储层联机宕机的情况。
解决办法:
保证缓存层的高可用性,个别节点宕机后依然可以提供服务
依赖隔离组件为后端限流并降级,在实际项目中,我们需要对重要的资源都进行隔离,让每种资源都运行在自己的线程池中,即便个别资源出现问题,对其他服务没有影响。降级的话则使用数据填充,不至于服务不可用。
对于如何保证高可用参考我之前写的文章:
快速搭建Redis Cluster集群 https://www.jianshu.com/p/4e4e5a18584d
基于Codis的Redis集群 https://www.jianshu.com/p/d175201e7e2c
除此之外还有一些KeepAlived,Redis哨兵等高可用解决方案
热点Key重建优化
当前key是一个热点的key,并发量非常的大,重建缓存不能再短时间内完成,缓存失效的瞬间,有大量的线程来重建缓存,造成后端负载加大,甚至应用崩溃。
解决办法:
减少重建缓存的次数,引入互斥锁。保证同一时间只有一个线程可以重建缓存。
数据尽可能一致
互斥锁方案表示:
数据尽可能一致的话,比如设置数据""永远不过期",不设置过期时间的同时,为每个value添加逻辑过期时间,当超过逻辑过期时间后,新开线程异步更新缓存
参考
[Redis开发与运维]
注:
本文独家发布自金蝶云社区