首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  程序员

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

  •  1
     
  •   maxxfire · 117 天前 · 3467 次点击
    这是一个创建于 117 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有一个事务需要做 2 件事:在文件系统中存储一个文件,同时在数据库生成一条记录。
    两者没有先后顺序的要求,但是要满足要么都成功,要么都失败。
    怎么才能做到这样,满足一致性(比如在突然断电情况下,也不影响结果),或者有什么措施能够尽量使数据可靠?
    37 回复  |  直到 2019-06-27 20:52:29 +08:00
        1
    sun1991   117 天前
    考虑数据一致性, 何不把文件存到数据库里去?
        2
    iwong0exv2   117 天前 via Android
    @sun1991 还要考虑查询啊
        3
    ace12   117 天前
    版本
        4
    des   117 天前 via Android
    是否有竞争、读写频率、不一致的接受程度、是否可以删除不说一下?
        5
    corvofeng   117 天前 via Android
    只存到数据库, 定时刷到文件里面, 类似缓存的用法不行吗?
        6
    maxxfire   117 天前
    @des 单线程操作,可以删除,性能要求不高
        7
    iwong0exv2   117 天前 via Android
    可参考 4 楼的思路,需要楼主自己完善下。
    另外再给个也许可行的方案:
    - 先写文件,再插入数据库。
    - 两个操作都成功才算成功;其中一个失败就回滚。
    - 读的时候以数据库表记录为准,数据库没有记录就算无效数据。
        8
    Vegetable   117 天前
    @iwong0exv2 +1

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

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

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

    如果要考虑删除、更新文件操作,那么就不一样了,2pc 或者其他
        19
    leonme   117 天前 via Android
    @wweir 老哥的方案是?
        20
    opengps   117 天前
    先把文件写成功在把结果存数据库会不会太慢?
    文件一般是允许多不能少,数据库则要求尽可能一一对应
        21
    janxin   117 天前
    同时写缓存和数据库,怎么保证一致性?
        22
    jaskle   117 天前 via Android
    事务回滚,写完文件再提交,写文件用写完后移动改名的方法,瞬间完成,若是失败回滚即可。但是要注意,频繁断电无法保证,甚至提交到数据库的内容都可能会丢失,经历过。
        23
    linyinma   117 天前
    Pos 机冲正概念应该你能用到: ( 1 )写冲正文件;( 2 )做些事情( A、B、C...);( 3 )删除冲正文件;

    ( 1 )做事情前修需要检测冲正文件,文件存在就要回滚(防止上一次掉电等原因事务未做完);
    ( 2 )事务完整就删冲正文件;
        24
    BBCCBB   117 天前
    用 2pc, tcc 这种思路。
        25
    petelin   117 天前 via iPhone
    Wal 日志
        26
    tabris17   117 天前
    预写日志,失败回滚
        27
    Mirana   117 天前
    写数据库失败了 需要删除文件?
        28
    Mitt   117 天前 via iPhone
    @wweir 你哪句话里看到说要强一致性了
        29
    prasanta   117 天前 via Android
    只能保证最终一致性,看你们的不一致时间窗口容忍度
        30
    IsaacYoung   117 天前
    single source of truth
        31
    anyuhanfei   117 天前
    这难道不是类似上传图片的基本操作?在逻辑层做判断呗
        32
    MeteorCat   117 天前 via Android
    文件一致性用文件的 hash 值就行了
        33
    DonaldY   117 天前
    话说计算文件 md5,不得把文件读取到服务器本地嘛,或者分块计算?
        34
    DonaldY   117 天前
    歪楼。

    话说计算文件 md5,不得把文件读取到服务器本地嘛,或者分块计算?

    请教下,大家一般怎么处理的?
        35
    husinhu   116 天前 via iPhone
    两个操作对应两个 fsync() 所以本质上要把这两个操作一起 commit。即便是 TxF 也不能保证能一起 rollback。要是我做就简单的 db as log,加一个 column 叫 filetxid,每次写完就写一行就 append 文件以 filetxid 作为前缀写完 fsync()落物理存储。每次恢复以 db 为准,如果文件末尾损坏做 replay。
        36
    husinhu   116 天前 via iPhone
    楼主是要存储文件不是写文件,我看错了嘿嘿,不过方法类似,db as wal log
        37
    troywinter   115 天前
    TCC,最终一致性,2pc 对业务不透明而且实现难度大,https://queue.acm.org/detail.cfm?id=1394128 参考 BASE 模型
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3015 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 31ms · UTC 11:03 · PVG 19:03 · LAX 04:03 · JFK 07:03
    ♥ Do have faith in what you're doing.