数据库缓存数据一致性保证
一、背景
在本文正式开始之前,需要先取得以下两点的共识:
a) 缓存必须要有过期时间
b) 保证数据库跟缓存的最终一致性即可,不必追求强一致性。
数据一致性指的是:
a) 缓存中存有数据,缓存的数据值 = 数据库中的值;
b) 缓存中没有该数据,数据库中的值 = 最新值
数据库跟缓存,毕竟是两套系统,如果要保证强一致性,势必要引入 2PC
或 Paxos
等分布式一致性协议,或者分布式锁等等,这个在实现上是有难度的,而且一定会对性能有影响。
在使用缓存时,通常有以下几种缓存使用策略用于提升系统性能:
1、读:
1)先读缓存,hit -> 返回数据
2)miss -> 从db中取出数据,放入缓存,同时返回数据
缺点:
由于数据仅在缓存未命中后才加载到缓存中,因此初次调用的数据请求响应时间会增加一些开销,因为需要额外的缓存填充和数据库查询耗时。
2、写(insert):
先写db后写缓存,db返回成功时,再写缓存。原因:
如果先写缓存,后写db,写db失败时,会导致只有缓存有数据,db无数据。数据库都不存在的数据,缓存存一份已经没意义了可视为脏数据。
3、写(update):
先更新db后删除缓存,为什么是删而不是更新缓存?
更新缓存在高并发下有可能出现脏数据:比如两个线程a,b先后到来,
1)a先更新db成功,在更新缓存时网卡了
2)b后更新db成功,并成功更新缓存
3)此时a才开始更新缓存,覆盖了b的数据
3.1、先更新db还是先删缓存?
如果先删缓存再更新db:假如删缓存成功了,更新db失败了,那么db中还是旧的值,缓存中无数据还会从db中拿到旧的值写到缓存里,pass此方案。所以要先更新db再删除缓存
3.2、先更新db后删缓存也会存在一些问题:
1)更新db成功,删缓存失败,在重试的过程中有读取请求进来,读到的还是旧数据。如果删缓存失败可以加异步重试直到删除成功为止。
2)在高并发下有可能出现脏数据,比如缓存过期时间到了,已经失效,此时两个线程读请求a,写请求b先后到来
a、读请求a发现缓存没数据,从db中读取数据,写缓存时网卡了
b、写请求b顺利的更新db删除缓存
c、此时读请求a恢复了,完成写缓存,把旧的值写入了缓存,此时缓存和db的数据已经不一致了
不过这个情况很难出现,因为数据库读操作是远快于写操作的(正是因为如此,才做读写分离),所以步骤b比步骤a更快不太可能出现,同时还要配合缓存刚好失效。
参考:https://mp.weixin.qq.com/s/r8VeAKkjMeResc4kKEovHw
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix