1.缓存的收益与成本
收益
- 加速读写
- 降低后端负载
- 后端服务器通过前端缓存降低负载,业务端使用Redis降低后端MySql等数据库负载
成本
- 数据不一致:缓存层和数据层有时间窗口不一致,和更新策略有关
- 代码维护成本增大:多了一层缓存逻辑
- 运维成本:例如Redis Cluster
2.缓存更新策略
- LRU、LFU、FIFO算法剔除:例如maxmemory-policy
- 设置过期时间:expire
- 主动更新:开发控制生命周期
建议
- 低一致性:最大内存和淘汰策略
- 高一致性:超市剔除和主动更新结合,最大内存和淘汰策略兜底
3.缓存粒度控制
可以从以下三个维度考虑
- 通用性:全量属性更好
- 占用空间:部分属性更好
- 代码维护:表面上全量属性更好
4.缓存穿透问题
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为0的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大
产生原因
- 业务代码自身原因
- 恶意攻击,爬虫等
如何发现
- 业务的响应时间
- 业务本身问题
- 相关指标:总调用数、缓存层命中数、存储层命中数
解决方案
- 缓存空对象:将查询到的null缓存到Redis中,并且设置过期时间。但这样会产生两个问题:1是需要更多的键,2是缓存层和存储层数据短期不一致(比如第一次查询数据库是null然后缓存了,第二次查询数据库已经有了但是缓存会返回null)
- 使用布隆过滤器拦截:
- 本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构,特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
- 当插入的元素越来越多时,当一个不在布隆过滤器中的元素,经过同样规则的哈希计算之后,得到的值在位数组中查询,有可能这些位置因为其他的元素先被置1了。所以布隆过滤器存在误判的情况,但是如果布隆过滤器判断某个元素不在布隆过滤器中,那么这个值就一定不在。
5.缓存雪崩问题
缓存雪崩是指在某一个时间段,缓存集中过期失效,不能正常工作了。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况
产生原因及解决
- 缓存大面积失效:避免缓存设置相近的有效期;为有效期增加随机值;统一规划有效期,失效时间均匀分布
- 对热点数据持续高并发:使用互斥锁:jvm锁机制;分布式锁机制
- 有效期本身的缺陷:缓存永不过期,异步更新
- 缓存服务器宕机:使用Redis哨兵模式或者Redis集群部署方式,即便个别Redis 节点下线,整个缓存层依然可以使用
6.热点key重建
比如微博某个大v发布了一条微博,此时将会有很大量的线程进入缓存重建,给数据库或底层造成很大的压力
目标
- 减少重新缓存的次数
- 数据尽可能一致
- 较少潜在的危险
解决方案
- 互斥锁:第一个线程进入重建缓存时,加上一把锁,等工作完成后,再把锁释放。锁定期间其他线程只能等待,等缓存重建成功后,从缓存中获取
- 永不过期:不设置过期时间expire,需要我们在程序中进行缓存的重建,重建完成之前获取到的都是旧的值
方案 | 优点 | 缺点 |
---|---|---|
互斥锁 | 思路简单、保证一致性 | 代码复杂度增加、存在死锁风险 |
永不过期 | 基本杜绝热点key重建问题 | 不保证一致性、逻辑过期时间增加维护成本和内存成本 |