缓存总结
Contents
缓存总结
1.使用场景
不经常变更的数据存到缓存中,减少db压力
2.缓存分类
1.分布式缓存redis/memcached
2.本地缓存cachetools/flask自带g
3.读操作缓存: 业务系统 读操作 > 写操作,减少db查询操作
4.写操作缓存: 业务系统 写操作 > 读操作,减少db写入操作
3.相关问题
3.1缓存穿透
如果查询的key一直不存在, 并发量大的情况下,造成db压力增大
解决:
可以将这个不存在的key预先设定一个值, 比如&&
首次查询如果缓存和db中均没有,设置该key对应的值为&&,这个失效时间设置短一些
再次查询如果查到key对应的value是&&, 则直接拦截
3.2缓存并发
高并发情况下, 缓存失效后, 可能出现多个进程同时查询db, 同时设置缓存的情况 造成db压力过大,缓存频繁更新的问题
解决:
对缓存查询加竞争锁,但是存在部分请求锁等待的问题
3.3缓存失效
高并发的情况下,存在某一时间缓存同时失效 解决:
缓存失效时间分散开,比如可以在原有失效时间的基础上增加一个随机值
失效时间可以分析用户行为,根据场景进行区分
3.4 缓存更新策略
1.LRU/LFU/FIFO算法剔除
使用场景: 剔除算法通常用于缓存使用量超过了预设的最大值时候,如何对现有的数据进行剔除。例如Redis使用maxmemory-policy这个配置作为内 存最大值后对于数据的剔除策略
一致性:
要清理哪些数据是由具体算法决定,开发人员只能决定使用哪种算法,所以数据的一致性是最差的
维护成本:
通常只需要配置最大maxmemory和对应的策略即可
2.超时剔除
使用场景:超时剔除通过给缓存数据设置过期时间,让其在过期时间后 自动删除 如果业务可以容忍一段时间内,缓存层数据和存储层数据不一致,那么可以为其设置过期时间。在数据过期 后,再从真实数据源获取数据,重新放到缓存并设置过期时间 如涉及交易方面的业务不可用
一致性:
一段时间窗口内(取决于过期时间长短)存在一致性问题,即 缓存数据和真实数据源的数据不一致
维护成本:
维护成本不是很高,只需设置expire过期时间即可,当然前 提是应用方允许这段时间可能发生的数据不一致
3.主动更新
使用场景: 应用方对于数据的一致性要求高,需要在真实数据更新后, 立即更新缓存数据。例如可以利用消息系统或者其他方式通知缓存更新
一致性:
一致性最高,但如果主动更新发生了问题,那么这条数据很可 能很长时间不会更新,所以建议结合超时剔除一起使用效果会更好
维护成本:
维护成本会比较高,开发者需要自己来完成更新,并保证更 新操作的正确性。
建议
低一致性业务建议配置最大内存和淘汰策略的方式使用
高一致性业务可以结合使用超时剔除和主动更新,这样即使主动更新 出了问题,也能保证数据过期时间后删除脏数据
根据我们自身的业务场景,API层面一致性要求不是很高,遂采用最大内存和超时剔除的方案
4.超时剔出策略
1.先更新数据库,再更新缓存
并发情况下,存在脏数据写入缓存
1.请求A更新db
2.请求B更新db
3.请求A更新cache
4.请求B更新cache
问题
可能由于处理,A最后才更新cache,导致cache中写入脏数据
如果缓存不设置expiret时间, 则一直存在脏数据的情况
2.先删除缓存,再更新数据库
1.请求A进行写操作,先删除cache
2.请求B查询缓存,不存在
3.请求B去数据库查询,得到旧值
4.请求B将旧值写入缓存
5.请求A将新值写入数据库
问题
如果缓存不设置expire时间, 则一直存在脏数据的情况
解决
延时双删 > A在更新db后再次删除cache
存在双删仍然失败的情况,则脏数据仍存在
3.先更新数据库,再删除缓存
1.缓存刚好失效
2.请求A查询数据库,得到一个旧值
3.请求B更新数据库
4.请求B删除cache
5.请求A将旧值写入cache
发生条件: 步骤3比步骤2耗时短,导致步骤4先于步骤5发生,但是步骤3是写操作,比较耗时, 所以以上概率很小 解决:
1.缓存加入过期时间
2.请求B更新db和删除cache之间,sleep, 延时删除
4.删除缓存失败重试机制
方案1
删除缓存的时,程序增加重试机制,如果失败,则扔到消息队列中 另一个任务定期读取消息队列,再次尝试删除
方案2
删除缓存的任务,交给订阅binlog程序处理,业务层面只需要更新数据库即可
5.缓存加载问题
如果缓存挂掉或者db字段有更新
解决:
项目加载或者db有变动的情况下,热加载db数据更新到缓存,减少db压力
6.缓存粒度控制
从MySQL获取用户信息
|
|
将用户信息缓存到Redis中: 缓存全部列:
|
|
缓存部分重要列
|
|
通用性:
缓存全部数据比部分数据更加通用,但从实际经验看,很长时 间内应用只需要几个重要的属性
空间占用:
缓存全部数据要比部分数据占用更多的空间,可能存在以下 问题
1.全部数据会造成内存的浪费
2.全部数据可能每次传输产生的网络流量会比较大,耗时相对较大,在 极端情况下会阻塞网络
3.全部数据的序列化和反序列化的CPU开销更大
代码维护:
全部数据的优势更加明显,而部分数据一旦要加新字段需要
修改业务代码,而且修改后通常还需要刷新缓存数据
参考: http://blog.jobbole.com/113992/ http://blog.didispace.com/chengchao-huancun-zuijiazhaoshi/ 《redis开发与运维》
Author tmackan
LastMod 2019-01-30