你们引入缓存中间件,会去解决数据库缓存双写一致性的问题吗

2021-06-03 16:57:23 +08:00
 zhongpingjing
看了一篇博文了解了一些相关的内容,了解到引起不一致性的原因:
先删缓存,再更新 DB (这种策略应该没有人用?)
先更新 DB,再删缓存(这种发生不一致性的概率虽然可以忽略不计,但是是否需要去防止?)
先更新 DB,然后删除缓存失败(真的会发生删除缓存失败吗?网络原因?)
DB 主从复制的延迟造成不一致
。。。

解决这个双写一致性问题,需要双删和重试。感觉这种方式代价有点大啊。
在实际生产中,会这样去解决吗?有没有更好的办法?
4054 次点击
所在节点    Java
29 条回复
wqhui
2021-06-03 17:16:31 +08:00
看业务是不是要求强一致性,还是说最终一致性也可以,强一致性的话代价肯定是大的了
BBCCBB
2021-06-03 17:17:47 +08:00
没有解决.. 不能容忍的地方我们都查 db.

只要两个地方没有事务. 总是有不一致的窗口存在.
vindac
2021-06-03 17:17:56 +08:00
我们都是缓存定时淘汰,有个服务去更新缓存。。
zhongpingjing
2021-06-03 18:01:02 +08:00
@vindac 意思是你们的业务服务自身不会去更新缓存是吗,那如果缓存过期了,会去查 DB 呢还是直接返回 null ?去查 DB 的话,查完会把结果放到缓存中吗?
abigeater
2021-06-03 18:02:58 +08:00
业务操作对缓存操作不直接写到 DB
服务定时将缓存写到 DB
读取从缓存读取 没有数据从 DB 读取后写到缓存
zhongpingjing
2021-06-03 18:04:55 +08:00
@vindac 专门的更新缓存服务,那要如何定位到失效缓存,如何更新它啊,比如缓存 A 过期了,缓存服务就需要去 DB 拉取数据放到缓存中,如何发现缓存 A 失效了,并及时更新它
raaaaaar
2021-06-03 18:06:18 +08:00
定时是个思想,大概可以参考下 cache 和内存的做法?没命中时再装载到 cache 里,满了就置换,根据修改位先写会再换什么的
zhongpingjing
2021-06-03 18:06:34 +08:00
@abigeater 这样有可能丢失数据
zhongpingjing
2021-06-03 18:08:35 +08:00
@raaaaaar 有点听不懂大佬在讲什么[笑哭]
InkAndBanner
2021-06-03 18:54:54 +08:00
@abigeater 从 DB 读 写到缓存里面不好吗?
potatowish
2021-06-03 18:58:29 +08:00
1.先更新 DB,再删缓存
2.订阅 binlog 日志去单独做更新,比如 canal
fkname
2021-06-03 19:00:07 +08:00
一般有缓存时间兜底
lsp7572
2021-06-03 19:15:36 +08:00
延时双删了解下
zhch602
2021-06-03 20:51:17 +08:00
@lsp7572 别误导人了,延迟双删也就面试八股文用用,真正生产中使用就是找死
iyaozhen
2021-06-03 21:07:27 +08:00
@zhch602 咦,为啥。比较简单有效
Croxx
2021-06-03 21:17:11 +08:00
leafre
2021-06-03 22:00:51 +08:00
删除缓存失败,那就补偿,直到成功为止,单机不一致解决
主从不一致使用选择性读主解决
ryd994
2021-06-04 07:42:59 +08:00
双删和后删有什么区别呢?
如果你速度快,别人速度慢,你更新完了别人再去取数据。和你先更新再删缓存又有什么区别?
如果你速度慢,别人速度快。别人把旧值取了,你再去把旧值再删一遍。

提供的保证是基本一样的,就是缓存对 db 的延迟一致性。考虑到写入者挂掉的情况,这甚至不是最终一致性。

你如果要求强一致,那只能用锁了。不那么蛋疼的办法就是:写一个中间件代理。对同一数据的请求由这同一台代理序列化。中间件可以在修改数据库的时候加锁。用本地锁实现了强一致。
但是现在问题就转移到了如何保证对同一数据的请求总是由同一代理处理的问题。看起来是 hash 一下不难。但是你得考虑代理服务器上线离线的情况。
bthulu
2021-06-04 09:00:36 +08:00
不管双删后删, 因网络问题, 都可能导致数据不一致.
如果需要最终一致性, 操作 db 时, 同时在数据库中标记一下需要更新的缓存, 因与 db 操作在同一数据库, 可以保证这里的强一致性.
然后再开定时任务从 db 中捞取需要更新缓存的数据, 去更新缓存, 更新成功后, 再清除此更新标记, 更新缓存失败, 不做处理, 等待下一次任务执行周期就行.
abigeater
2021-06-04 11:33:26 +08:00
@InkAndBanner em..你这里是 从 DB 读,写到缓存吗 还是从 DB 读写到缓存 这个空格分的不够开不知道是哪个意思
1.从 DB 读,写到缓存:我这用定时服务从缓存写到 DB 那如果从 DB 读 就会有个时间差 定时服务还没写进 DB 时被读取就会拿到旧数据 那数据就不一致了
2.从 DB 读写缓存:就是这个意思,只是把从缓存写回到 DB 的压力减少

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/781166

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX