V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
zzkde
V2EX  ›  问与答

向文件追加数据的时候发生断电之类的故障,会怎样?

  •  1
     
  •   zzkde · 2021-03-25 23:39:21 +08:00 · 1116 次点击
    这是一个创建于 1121 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在写 wal 的实现的时候,不知道如何处理 append 数据时如果发生断电之类的故障如何保证数据安全,想知道如果发生这样的情况会是怎样的,可能是数据只写了一半?也不知道新写入数据时发生故障是否会影响之前写入的内容。我现在的实现是每个 LogEntry 加个 crc 校验字段,在读取数据时检验一下数据时用 crc 校验一下数据。

    看了 etcd 的 wal 实现,好像如果发生这样的情况,扇区的情况是全 zero 。

    大概流程就是校验一下 crc,不对就进入 isTornEntry 逻辑判断数据所在的扇区是否存在全 zero 的情况。

    if err := rec.Validate(d.crc.Sum32()); err != nil {
    	if d.isTornEntry(data) {
    		return io.ErrUnexpectedEOF
    	}
    	return err
    }
    
    isTornEntry 函数的主要逻辑
    // if any data for a sector chunk is all 0, it's a torn write
    for _, sect := range chunks {
    	isZero := true
    	for _, v := range sect {
            if v != 0 {
                isZero = false
                break
            }
    	}
        if isZero {
        	return true
        }
    }
    

    etcd 的 wal 源码

    5 条回复    2021-03-26 13:56:48 +08:00
    liprais
        1
    liprais  
       2021-03-26 00:06:36 +08:00
    "The other consideration is to make sure that corrupted log files are detected while reading the log. To handle this, log entries are generally written with the CRC records, which then can be validated when the files are read. "
    https://martinfowler.com/articles/patterns-of-distributed-systems/wal.html
    你的实现看起来没啥问题
    wakzz
        2
    wakzz  
       2021-03-26 09:07:10 +08:00
    你这个其实是在问数据落盘的方案,现在的主流方式有:
    1. Double Write
    2. Shadow Paging
    3. Trans Log
    4. 每次全量写(Redis 的 RDB)
    wakzz
        3
    wakzz  
       2021-03-26 09:11:05 +08:00
    程序应该自己保证数据落盘后文件完整性,就算写入中途突然断电中断导致数据页损坏,也可以通过应用本身的逻辑处理,或恢复成正确的旧数据,或接着断电前继续写新数据,而不会出现数据错乱的情况。
    zzkde
        4
    zzkde  
    OP
       2021-03-26 12:50:24 +08:00
    @wakzz Double Write 和 Shadow Paging 关注的是数据页的写入,Trans Log 就是 wal 。无法解决我当前的疑惑啊
    @liprais 赞!这篇文章刚好我也看了,但是里面没有更多的实现细节
    wakzz
        5
    wakzz  
       2021-03-26 13:56:48 +08:00
    @zzkde 常见的是 Trans Log 和 Double Write 组合,数据更新时先添加 Trans Log,如果 Trans Log 写入失败则操作失败,每一条 Trans Log 都有完整校验,应用重启恢复读取 Trans Log 时完整校验没过 的 log 直接忽略。
    然后数据写入通过 Double Write 方式,Double Write 是写两次,如果是第二次写失败可以通过第一次写的数据恢复;如果是第一次写失败,则可以通过 Trans Log 和原本的数据副本恢复。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   936 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 20:26 · PVG 04:26 · LAX 13:26 · JFK 16:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.