同时写文件和数据库,如何保证数据一致性?

2019-06-25 21:02:29 +08:00
 maxxfire
有一个事务需要做 2 件事:在文件系统中存储一个文件,同时在数据库生成一条记录。
两者没有先后顺序的要求,但是要满足要么都成功,要么都失败。
怎么才能做到这样,满足一致性(比如在突然断电情况下,也不影响结果),或者有什么措施能够尽量使数据可靠?
6753 次点击
所在节点    程序员
37 条回复
sun1991
2019-06-25 21:12:14 +08:00
考虑数据一致性, 何不把文件存到数据库里去?
iwong0exv2
2019-06-25 21:15:19 +08:00
@sun1991 还要考虑查询啊
ace12
2019-06-25 21:17:03 +08:00
版本
des
2019-06-25 21:19:04 +08:00
是否有竞争、读写频率、不一致的接受程度、是否可以删除不说一下?
corvofeng
2019-06-25 21:19:40 +08:00
只存到数据库, 定时刷到文件里面, 类似缓存的用法不行吗?
maxxfire
2019-06-25 21:22:21 +08:00
@des 单线程操作,可以删除,性能要求不高
iwong0exv2
2019-06-25 21:36:41 +08:00
可参考 4 楼的思路,需要楼主自己完善下。
另外再给个也许可行的方案:
- 先写文件,再插入数据库。
- 两个操作都成功才算成功;其中一个失败就回滚。
- 读的时候以数据库表记录为准,数据库没有记录就算无效数据。
Vegetable
2019-06-25 21:41:53 +08:00
@iwong0exv2 +1

你直接考虑查询,实际上查不到就意味着操作是失败的,查得到就是成功的.所以你只需要保证数据库里的记录,都有对应的文件,而不需要严格保证每个文件都对应了数据库的条目.
只有这样你才能保证突然断电了也不会出现查询的时候出错,因为写数据库是最后一步.

但是如果是对现有文件进行修改的话就比较麻烦咯
linbiaye
2019-06-25 21:45:01 +08:00
1.计算文件 md5 ; 2.记日志(比如某张表中插入一条记录包含 md5, filepath ;或者日志文件 -> md5 为文件名,内容 filepath ); 3. 写文件; 4. 写文件成功后写表; 5. 如果 2 个写都成功或者任意一个不成功则删除日志。6. 系统恢复或者重启后检查日志,如果文件 md5 值不匹配认为则删除脏数据,若匹配则跳转到第 4 步或者跳转到第 5 步。
carlclone
2019-06-25 21:53:50 +08:00
这完全就是 mysql 里 redolog 和 binlog 的场景 , 两阶段提交
mysql 写完了先处于 prepare 状态 , 如果文件系统写入成功了则提交 , 没成功事务就回滚了
GavinAlison
2019-06-25 22:12:08 +08:00
@linbiaye +1

1. 计算文件的 md5
2. 记录操作日志,比如这条记录的信息,包括文件的 md5, filename, filePath, meta 信息
3. 开始写入数据库,先记录入库的日志,写入数据库中,利用数据库的事物保证写入成功,失败记录失败日志
4. 开始写入文件,先记录写文件日志,在写入文件,更具 md5 值,从 mongodb 中查询对应的数据,如果有删除,排除中断上传的问题,重新上传, 失败重试,记录写入重试次数,败次数超过 5 次,写入失败日志
5. 成功之后,返回主程序,记录成功日志。
ihciah
2019-06-25 23:55:48 +08:00
2PC
vindurriel
2019-06-26 00:29:10 +08:00
begin; insert; err=writeFile(); if err then rollback; else commit;
wweir
2019-06-26 04:58:24 +08:00
强一致是一定做不到,只能考虑最终一致。这样的话,写个事后检查就可以了
wweir
2019-06-26 04:59:48 +08:00
不得不说,不懂装懂的好多……
jorneyr
2019-06-26 07:48:23 +08:00
写之前保存一个开始事务的标记,都成功后再保存一个操作成功的记录,如果失败就回滚 (回滚逻辑根据你的业务逻辑来实现),和分布式事务差不多一个道理。
Huelse
2019-06-26 08:12:07 +08:00
一般选择单线程,先文件后数据库,成功标记可选择返回或者数据库记录。也可不返回,进行事后检查确认两者
rrfeng
2019-06-26 08:32:54 +08:00
要看写文件是什么场景,如果是对象存储,只有添加新文件而没有更新操作,那么完全可以写文件然后写数据库,因为多写了文件并不影响一致性(多了一些没有索引的文件而已,而且如果重新上传被覆盖也没问题)

如果要考虑删除、更新文件操作,那么就不一样了,2pc 或者其他
leonme
2019-06-26 08:50:21 +08:00
@wweir 老哥的方案是?
opengps
2019-06-26 08:52:53 +08:00
先把文件写成功在把结果存数据库会不会太慢?
文件一般是允许多不能少,数据库则要求尽可能一一对应

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

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

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

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

© 2021 V2EX