为什么需要缓存更新?
使用缓存后,数据可能同时保存在数据库与缓存当中。如果数据库的数据改变,而缓存中的数据没有改变,就会导致数据不一致的问题。
常见的缓存更新策略
内存淘汰 | 超时剔除 | 主动更新 | |
---|---|---|---|
概述 | redis自带的内存淘汰机制,当内存不足时自动淘汰部分数据 | 手动给缓存的数据添加TTL时间,到期后自动删除 | 编写业务逻辑,更新数据库数据后同步更新缓存 |
解决数据一致性的问题 | 差 | 一般 | 好 |
使用成本 | 无 | 低 | 高 |
关于内存淘汰机制解决数据一致性:
若只依靠内存淘汰机制,可能会出现这种问题:内存淘汰机制一直未执行,所以缓存中的数据一直未更新,而数据库中的数据已经改变。
不同策略合适的业务场景:
- 低一致性需求:就是数据长久不会发生变化的情况下,使用内存淘汰机制。例如查询店铺类型缓存。
- 高一致性需求:使用主动更新策略,并使用超时剔除作为兜底方案。例如查询店铺详情。
主动更新
主动更新目前我了解的三种实现方法:
- 由缓存的调用者,在更新数据库时同时更新缓存
- 将缓存与数据库整合为一个服务,由服务来维护一致性,调用者无需关心缓存一致性问题
- crud在缓存中进行,由其他线程异步的将缓存数据持久化到数据库。
三种方法中,个人认为最好的就是第一种,实现简单且能较好的解决数据一致性问题。但是在同时操作数据库和缓存时,有以下三个问题:
-
删除缓存还是更新缓存?
更新缓存
:每次更新数据库都要更新缓存,会增加写操作,很可能会写多读少,消耗资源来进行无效写操作。删除缓存
:更新数据库时,让缓存失效,当再次查询时再更新缓存。 -
如何保证缓存与数据库的操作同时成功或失败?(原子性问题)
单体系统
:将缓存和数据库放在同一个事务中分布式系统
:利用TTC
等分布式事务方案 -
先操作缓存还是先操作数据库?(线程安全问题)
假设缓存中有数据v=10,现在修改了v=20。分别以两种操作方式来讨论:
先删缓存再操作数据库:
理想情况:
1. 线程1删除缓存
2. 线程1数据库更新数据v=20
3. 线程2查询数据,缓存未命中
4. 线程2将数据库中的v=20写入缓存
异常情况:
1. 线程1删除缓存,线程1结束
2. 线程2查询数据未命中
3. 线程2从数据库读取v=10写入缓存
4. 线程1更新数据库数据v=20
数据库数据和缓存数据不一致,发生概率高,因为redis操作数据库快,而数据库操作慢
先操作数据库再删除缓存:
理想情况:
异常情况:
1. 缓存中的数据失效
2. 线程1查询缓存未命中,查询数据库,将v=10传递给用户,线程1结束
3. 线程2更新数据库,v=20写入数据库
4. 线程2删除缓存,但是这个缓存已经是失效的了,线程2结束
5. 线程2写入缓存v=20
这种情况发送的较少,需要以下条件:
- 两个线程并行执行
- 线程1查询时,恰好缓存失效
- 线程1写缓存时,恰好切换到了线程2
- 线程2恰好更新数据库
两种情况都可能会发生线程安全问题,但是先操作数据库再操作缓存这种方案发生线程安全的可能性更小。
总结:
标签:缓存,20,数据库,Redis,更新,线程,数据 来源: https://www.cnblogs.com/wangxiaojie233/p/16378851.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。