V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
cc959798
V2EX  ›  问与答

mysql 为什么不能仅仅用 binlog 保证不丢数据

  •  
  •   cc959798 · Nov 26, 2018 · 4888 views
    This topic created in 2710 days ago, the information mentioned may be changed or developed.

    mysql 配置每次事务 commit binlog 都写磁盘感觉也不会丢数据,为什么要使用 redo log 一块保证 crash safe 呢?仅仅用 binlog 不可以吗

    20 replies    2018-11-27 09:57:00 +08:00
    msg7086
        1
    msg7086  
       Nov 26, 2018
    我刚刚随便谷歌了一下,看到不少文章说这个的。你也可以试试看。
    简单说,binlog 发生在 redolog 之后。
    cc959798
        2
    cc959798  
    OP
       Nov 26, 2018
    @msg7086 是不少,我也看了一些,但是可能理解的都不太对,binlog 发生在后面这个我也知道,但是就是感觉没有 redo 也能保持不丢数据,只是不能保证未提交到事务不能恢复,但是感觉未提交到事务不恢复就不恢复呗,反正未提交
    monsterxx03
        4
    monsterxx03  
       Nov 26, 2018
    楼主应该是认为 MySQL 每次写入数据的时候直接写入磁盘(ibd 文件), 但实际上写的是 WAL(write ahead log), 然后客户端就收到成功的返回了, 因为数据真正落地是随机写, 写 WAL 是顺序写, 要快得多. binlog 的生成应该在数据正真落地之后.

    crash 重启后, ibd 文件不一定是最新的, 需要用 WAL 里的 redo log 来恢复数据.
    cc959798
        5
    cc959798  
    OP
       Nov 26, 2018
    @monsterxx03 不是,我是说写 log,binlog 也是 log,也能恢复数据不是吗?为什么还需要 redo log 来恢复数据,仅仅是为了恢复未提交的事务吗
    cc959798
        6
    cc959798  
    OP
       Nov 26, 2018
    @opennet 看过了,但是没说为什么必须要用 redo log 和 binlog 结合方式来恢复数据,我觉得用 binlog 也是可以的
    ebony0319
        7
    ebony0319  
       Nov 26, 2018 via Android
    先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。
    但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
    然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

    先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1 ”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。
    但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
    然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

    先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1 ”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这先写 redo log 后写 binlog。假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1。
    但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
    然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。

    先写 binlog 后写 redo log。如果在 binlog 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 binlog 里面已经记录了“把 c 从 0 改成 1 ”这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。
    ebony0319
        8
    ebony0319  
       Nov 26, 2018 via Android
    我取的也是 林晓斌 的原话,已经解释非常清楚了。
    cc959798
        9
    cc959798  
    OP
       Nov 26, 2018
    @ebony0319 大佬你复制多了,这些我也是看明白了,我的意思 如果把 binlog 放在事务 commit 之前写入的话,这样也可以保证数据不丢失,比如 log 写了,然后断电,这个时候虽然没 commit,但是 commit 是最后一步了,也可以算作已经 commit 了,这样可以恢复数据,如果是 log 写之前就断电,ccommit 还没提交,就不会有新的这条数据,也会是合理的


    换句话说,我们不写日志,commit 时 直接写数据到磁盘(虽然是有性能问题),但是也是可以保证数据断电不丢失(除非磁盘坏了)
    GaryZ
        10
    GaryZ  
       Nov 26, 2018
    我觉得是数据恢复的时候是否能保持一致性的问题吧
    monsterxx03
        11
    monsterxx03  
       Nov 26, 2018
    @cc959798 大概明白你的意思了, MySQL 支持不只一种存储引擎, 各种不同的存储引擎都能开 binlog (用于获取 ongoing change, master/slave), 但 redo/undo log 是 innodb 专属的. 它们工作在不同层面上.

    如果设计一个 innodb 专属的 MySQL, 的确可以只保留一种 log, 比如 aws 的 aurora db, master/slave 之间就是通过 redo log 同步的( 当然 binlog 也可以开)
    ebony0319
        12
    ebony0319  
       Nov 26, 2018 via Android
    是不是可以这样理解。每种成功的概率是 0.9,那么两份备份失败的概率等于 1-0.1*0.1=0.99 ?
    ebony0319
        13
    ebony0319  
       Nov 26, 2018 via Android
    而且 redo log 是 Innodb 特有的。
    cc959798
        14
    cc959798  
    OP
       Nov 26, 2018
    @monsterxx03 嗯嗯,这些都知道,redo 是在存储引擎层面的,但是就是奇怪,binlog 可以实现断电恢复,为什么还要加个 redo log
    msg7086
        15
    msg7086  
       Nov 26, 2018
    binlog 没有 redo log 那么牛逼。
    redo log 是事务边跑边写的,commit 的时候只要 mark 一下就行了。binlog 得要整个事务确定 commit 或者 rollback 才会一次性写入,可靠性哪有 redo log 高。


    @ebony0319 你可以理解成 binlog 成功的概率是 0.8,而 redo log 成功的概率是 0.98 。因为有个 0.8 的 binlog 所以把 0.98 的 redo log 去掉是很得不偿失的。
    cc959798
        16
    cc959798  
    OP
       Nov 26, 2018
    @ebony0319 仅仅是这样吗?如果 binlog 每次事务都写磁盘的话理论上数据也是不会丢失的,没写成功不让 commit,这样不就可以了。难道仅仅是因为存储引擎不能控制 binlog 或者说存储引擎不关心 binlog 而作的一种妥协?
    monsterxx03
        17
    monsterxx03  
       Nov 26, 2018
    有点钻牛角尖了额, 你先做了个假设: 把 binlog 提前到 commit 之前写,然后就能用 binlog 来做 crash recover.

    问题是目前 binlog 和 redo log 的实现格式完全不同(binlog 根据你需求可选三种呢). 刷盘机制也完全不同. 虽然我不了解这块代码的实现, 但工程上硬用 binlog 来实现 crash recovery 感觉是不行的.(你想想还有 semi sync 的同步方式呢, 同步这块相当复杂)

    binlog 的设计目的是为了让外部系统获取数据库内的数据变更,可以理解成一个 expose 的接口.

    redo 是 innodb 为了达成 acid, crash recovery 的一种内部实现手段.

    存储引擎的确不能控制 binlog, 也不应该关心 binlog, 这不算妥协, 是 by design.
    monsterxx03
        18
    monsterxx03  
       Nov 26, 2018
    还有目前的 binlog 并不能实现断电恢复, binlog 可以做 point-in-time recovery 这个一般是写坏数据了用来修数据的.
    cc959798
        19
    cc959798  
    OP
       Nov 26, 2018
    @monsterxx03 嗯嗯你这么说感觉也是有道理的
    julyclyde
        20
    julyclyde  
       Nov 27, 2018
    binlog 其实是个外挂式的东西
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3332 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 47ms · UTC 13:08 · PVG 21:08 · LAX 06:08 · JFK 09:08
    ♥ Do have faith in what you're doing.