etcd源码阅读(三):wal

栏目: 后端 · 发布时间: 7年前

内容简介:今天来看看WAL(Write-Ahead Logging)。这是数据库中保证数据持久化的常用技术,即每次真正操作数据之前,先往磁盘上追加一条日志,由于日志 是追加的,也就是顺序写,而不是随机写,所以写入性能还是很高的。这样做的目的是,如果在写入磁盘之前发生崩溃,那么数据肯定是没有写入 的,如果在写入后发生崩溃,那么还是可以从WAL里恢复出来。首先看一下我们先阅读

今天来看看WAL(Write-Ahead Logging)。这是数据库中保证数据持久化的常用技术,即每次真正操作数据之前,先往磁盘上追加一条日志,由于日志 是追加的,也就是顺序写,而不是随机写,所以写入性能还是很高的。这样做的目的是,如果在写入磁盘之前发生崩溃,那么数据肯定是没有写入 的,如果在写入后发生崩溃,那么还是可以从WAL里恢复出来。

首先看一下 wal 里有什么:

$ tree
.
├── decoder.go
├── doc.go
├── encoder.go
├── file_pipeline.go
├── file_pipeline_test.go
├── metrics.go
├── record_test.go
├── repair.go
├── repair_test.go
├── util.go
├── wal.go
├── wal_bench_test.go
├── wal_test.go
└── walpb
    ├── record.go
    ├── record.pb.go
    └── record.proto

1 directory, 16 files

我们先阅读 doc.go ,可以知道这些东西:

w.Save
w.Close

我们看看 Save 的实现:

func (w *WAL) Save(st raftpb.HardState, ents []raftpb.Entry) error {
    w.mu.Lock()
    defer w.mu.Unlock()

    // short cut, do not call sync
    if raft.IsEmptyHardState(st) && len(ents) == 0 {
        return nil
    }

    mustSync := raft.MustSync(st, w.state, len(ents))

    // TODO(xiangli): no more reference operator
    for i := range ents {
        if err := w.saveEntry(&ents[i]); err != nil {
            return err
        }
    }
    if err := w.saveState(&st); err != nil {
        return err
    }

    curOff, err := w.tail().Seek(0, io.SeekCurrent)
    if err != nil {
        return err
    }
    if curOff < SegmentSizeBytes {
        if mustSync {
            return w.sync()
        }
        return nil
    }

    return w.cut()
}

可以看出来, Save 做的事情,就是写入一条记录,然后调用 w.sync ,而 w.sync 做的事情就是:

func (w *WAL) sync() error {
    if w.encoder != nil {
        if err := w.encoder.flush(); err != nil {
            return err
        }
    }
    start := time.Now()
    err := fileutil.Fdatasync(w.tail().File)

    took := time.Since(start)
    if took > warnSyncDuration {
        if w.lg != nil {
            w.lg.Warn(
                "slow fdatasync",
                zap.Duration("took", took),
                zap.Duration("expected-duration", warnSyncDuration),
            )
        } else {
            plog.Warningf("sync duration of %v, expected less than %v", took, warnSyncDuration)
        }
    }
    walFsyncSec.Observe(took.Seconds())

    return err

调用了 fileutil.Fdatasync ,而 fileutil.Fdatasync 就是调用了 fsync 这个系统调用保证数据会被写到磁盘。

而快照也是类似的,写入一条记录,然后同步。

func (w *WAL) SaveSnapshot(e walpb.Snapshot) error {
    b := pbutil.MustMarshal(&e)

    w.mu.Lock()
    defer w.mu.Unlock()

    rec := &walpb.Record{Type: snapshotType, Data: b}
    if err := w.encoder.encode(rec); err != nil {
        return err
    }
    // update enti only when snapshot is ahead of last index
    if w.enti < e.Index {
        w.enti = e.Index
    }
    return w.sync()
}

WAL更多的是对多个WAL文件进行管理,WAL文件的命名规则是 $seq-$index.wal 。第一个文件会是 0000000000000000-0000000000000000.wal , 此后,如果文件大小到了64M,就进行一次cut,比如,第一次cut的时候,raft的index是20,那么文件名就会变成 0000000000000001-0000000000000021.wal

WAL就看到这。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Mechanics of Web Handling

The Mechanics of Web Handling

David R. Roisum

This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具