11.1 缓存更新策略
分别从使用场景、一致性、开发维护成本三个角度分析三种缓存更新策略。
1 LRU/LFU/FIFO 淘汰策略
使用场景:当缓存的大小超过了设置的内存最大值时,需要根据淘汰策略对多出的数据进行清除;
一致性: 一致性较差, 清除的数据是由淘汰策略算法决定;
开发成本:开发成本较低,只需要设置maxmemory和淘汰策略算法即可,不需要额外的开发工作。
2 超时剔除
使用场景:业务上允许缓存层和数据层在一段时间可以不同, 可以使用此方式。 对缓存的数据设置过期
时间,当超过了过期时间缓存会自动清除掉, 下次在访问时,会从数据库从获取最新的数据到缓存中;
一致性: 一致性差, 一段时间缓存层和数据层属于不一致;
开发成本: 开发成本低,只需要设置缓存的过期时间即可。
3 主动更新
使用场景: 当需要缓存层的数据和数据库层数据一致性要求高,当数据更新时,需要实时更新到缓存层;
一致性:一致性较高;
开发成本:开发成本高,当数据更新时需要同步维护缓存数据。
三种缓存策略实际使用总结:
1)对缓存数据一致性要求不高, 可以设置最大内存和选择淘汰策略这种方式;
2)对缓存数据要求实时性高,需要用主动更新加超时剔除一起使用,避免主动更新出问题后,能及时清除掉
失效的缓存。
11.2 缓存的粒度
在实际使用缓存的时候,缓存所有属性还是部分属性, 需要从通用性、空间占用、代码维护三个维度分析。
通用性: 缓存所有属性通用性好,但是实际工作上,在很长的一段时间只是维护几个属性字段;
空间占用: 缓存所有属性会占用更多的内存,数据在序列化和反序列化会占用更多cpu资源;
代码维护: 缓存所有属性维护成本低, 而部分属性如果有变动需要经常更新代码。
总结:
实际使用过程, 要根据实际情况, 从通用性、空间占用、代码维护三个维度取舍。
11.3 缓存击穿
1. 击穿的过程
1) 缓存层中没有查询到数据
2) 存储层也没有查询到数据, 不将空结果返回给缓存;
3) 直接返回空结果
2. 原因
1)程序问题;
2)恶意攻击导致大批量查询不命中缓存。
3. 解决方案
1) 缓存空对象
从存储层未查询到数据,会先把空对象缓存起来, 之后在返回给客户端空值。
存在的问题:
当空对象存储的越来越多,会占用大量内存, 解决方式, 可以用为这些空对象的key设置极端超时时间,
过期后自动清除。
2) 布隆过滤器
在缓存层和存储层之前增加一个布隆过滤器, 专门存储key值存在的key,如果查询的数据不存在key,
会被过滤器直接过滤掉, 从而实现了第一层过滤。
两种方案的对比:
实际使用中, 需要根据适用场景、维护成本去权衡使用哪种方式。
11.4 缓存雪崩
1. 原因
当缓存层出现故障,导致所有请求都直接访问存储层,造成存储层负载过重,严重会把存储层搞崩溃。
2. 解决方案
1) 高可用设置
redis的哨兵、集群都能保证缓存的高可用
2)依赖隔离组件为后端限流并降级