1
sun1991 2019-06-25 21:12:14 +08:00
考虑数据一致性, 何不把文件存到数据库里去?
|
2
iwong0exv2 2019-06-25 21:15:19 +08:00 via Android
@sun1991 还要考虑查询啊
|
3
ace12 2019-06-25 21:17:03 +08:00
版本
|
4
des 2019-06-25 21:19:04 +08:00 via Android
是否有竞争、读写频率、不一致的接受程度、是否可以删除不说一下?
|
5
corvofeng 2019-06-25 21:19:40 +08:00 via Android
只存到数据库, 定时刷到文件里面, 类似缓存的用法不行吗?
|
7
iwong0exv2 2019-06-25 21:36:41 +08:00 via Android
可参考 4 楼的思路,需要楼主自己完善下。
另外再给个也许可行的方案: - 先写文件,再插入数据库。 - 两个操作都成功才算成功;其中一个失败就回滚。 - 读的时候以数据库表记录为准,数据库没有记录就算无效数据。 |
8
Vegetable 2019-06-25 21:41:53 +08:00
@iwong0exv2 +1
你直接考虑查询,实际上查不到就意味着操作是失败的,查得到就是成功的.所以你只需要保证数据库里的记录,都有对应的文件,而不需要严格保证每个文件都对应了数据库的条目. 只有这样你才能保证突然断电了也不会出现查询的时候出错,因为写数据库是最后一步. 但是如果是对现有文件进行修改的话就比较麻烦咯 |
9
linbiaye 2019-06-25 21:45:01 +08:00 1
1.计算文件 md5 ; 2.记日志(比如某张表中插入一条记录包含 md5, filepath ;或者日志文件 -> md5 为文件名,内容 filepath ); 3. 写文件; 4. 写文件成功后写表; 5. 如果 2 个写都成功或者任意一个不成功则删除日志。6. 系统恢复或者重启后检查日志,如果文件 md5 值不匹配认为则删除脏数据,若匹配则跳转到第 4 步或者跳转到第 5 步。
|
10
carlclone 2019-06-25 21:53:50 +08:00
这完全就是 mysql 里 redolog 和 binlog 的场景 , 两阶段提交
mysql 写完了先处于 prepare 状态 , 如果文件系统写入成功了则提交 , 没成功事务就回滚了 |
11
GavinAlison 2019-06-25 22:12:08 +08:00
@linbiaye +1
1. 计算文件的 md5 2. 记录操作日志,比如这条记录的信息,包括文件的 md5, filename, filePath, meta 信息 3. 开始写入数据库,先记录入库的日志,写入数据库中,利用数据库的事物保证写入成功,失败记录失败日志 4. 开始写入文件,先记录写文件日志,在写入文件,更具 md5 值,从 mongodb 中查询对应的数据,如果有删除,排除中断上传的问题,重新上传, 失败重试,记录写入重试次数,败次数超过 5 次,写入失败日志 5. 成功之后,返回主程序,记录成功日志。 |
12
ihciah 2019-06-25 23:55:48 +08:00
2PC
|
13
vindurriel 2019-06-26 00:29:10 +08:00 via iPhone
begin; insert; err=writeFile(); if err then rollback; else commit;
|
14
wweir 2019-06-26 04:58:24 +08:00 via Android
强一致是一定做不到,只能考虑最终一致。这样的话,写个事后检查就可以了
|
15
wweir 2019-06-26 04:59:48 +08:00 via Android
不得不说,不懂装懂的好多……
|
16
jorneyr 2019-06-26 07:48:23 +08:00
写之前保存一个开始事务的标记,都成功后再保存一个操作成功的记录,如果失败就回滚 (回滚逻辑根据你的业务逻辑来实现),和分布式事务差不多一个道理。
|
17
Huelse 2019-06-26 08:12:07 +08:00
一般选择单线程,先文件后数据库,成功标记可选择返回或者数据库记录。也可不返回,进行事后检查确认两者
|
18
rrfeng 2019-06-26 08:32:54 +08:00
要看写文件是什么场景,如果是对象存储,只有添加新文件而没有更新操作,那么完全可以写文件然后写数据库,因为多写了文件并不影响一致性(多了一些没有索引的文件而已,而且如果重新上传被覆盖也没问题)
如果要考虑删除、更新文件操作,那么就不一样了,2pc 或者其他 |
20
opengps 2019-06-26 08:52:53 +08:00
先把文件写成功在把结果存数据库会不会太慢?
文件一般是允许多不能少,数据库则要求尽可能一一对应 |
21
janxin 2019-06-26 11:38:37 +08:00
同时写缓存和数据库,怎么保证一致性?
|
22
jaskle 2019-06-26 12:43:11 +08:00 via Android
事务回滚,写完文件再提交,写文件用写完后移动改名的方法,瞬间完成,若是失败回滚即可。但是要注意,频繁断电无法保证,甚至提交到数据库的内容都可能会丢失,经历过。
|
23
linyinma 2019-06-26 12:46:27 +08:00
Pos 机冲正概念应该你能用到: ( 1 )写冲正文件;( 2 )做些事情( A、B、C...);( 3 )删除冲正文件;
( 1 )做事情前修需要检测冲正文件,文件存在就要回滚(防止上一次掉电等原因事务未做完); ( 2 )事务完整就删冲正文件; |
24
BBCCBB 2019-06-26 13:21:18 +08:00
用 2pc, tcc 这种思路。
|
25
petelin 2019-06-26 13:46:58 +08:00 via iPhone
Wal 日志
|
26
tabris17 2019-06-26 13:48:09 +08:00
预写日志,失败回滚
|
27
Mirana 2019-06-26 13:53:30 +08:00
写数据库失败了 需要删除文件?
|
29
prasanta 2019-06-26 14:03:29 +08:00 via Android
只能保证最终一致性,看你们的不一致时间窗口容忍度
|
30
IsaacYoung 2019-06-26 14:16:23 +08:00
single source of truth
|
31
anyuhanfei 2019-06-26 17:18:07 +08:00
这难道不是类似上传图片的基本操作?在逻辑层做判断呗
|
32
MeteorCat 2019-06-26 17:25:39 +08:00 via Android
文件一致性用文件的 hash 值就行了
|
33
DonaldY 2019-06-26 17:37:50 +08:00
话说计算文件 md5,不得把文件读取到服务器本地嘛,或者分块计算?
|
34
DonaldY 2019-06-26 17:38:33 +08:00
歪楼。
话说计算文件 md5,不得把文件读取到服务器本地嘛,或者分块计算? 请教下,大家一般怎么处理的? |
35
husinhu 2019-06-26 20:01:47 +08:00 via iPhone
两个操作对应两个 fsync() 所以本质上要把这两个操作一起 commit。即便是 TxF 也不能保证能一起 rollback。要是我做就简单的 db as log,加一个 column 叫 filetxid,每次写完就写一行就 append 文件以 filetxid 作为前缀写完 fsync()落物理存储。每次恢复以 db 为准,如果文件末尾损坏做 replay。
|
36
husinhu 2019-06-26 20:04:25 +08:00 via iPhone
楼主是要存储文件不是写文件,我看错了嘿嘿,不过方法类似,db as wal log
|
37
troywinter 2019-06-27 20:52:29 +08:00
TCC,最终一致性,2pc 对业务不透明而且实现难度大,https://queue.acm.org/detail.cfm?id=1394128 参考 BASE 模型
|
38
chaleaochexist 77 天前
大佬遇到了同样的问题, 请问最后是如何解决的?
|