WAL简介
使用过存储软件的都知道,为了应对写入性能和灾难恢复,各个存储软件都有相关的机制来保障, 比如:
mysql的redo log 和undo log
zookeeper的事务日志
etcd的wal日志
等等,那为啥都需要额外写入这样一种日志呢?
因为离散写的场景下会造成过多的随机写,更合理的方式是顺序 io 写到一个日志文件里,然后等待时机把数据进行合并后变更数据文件,这个日志就是 wal ( write ahead log) 预写日志.
另外还有一点,直接修改数据文件的话,如果写到一半发生了 crash,那么该页就损坏了.
如果 DB 关了或者挂了,但还有部分数据在内存和 wal 日志中,还未变更到 db 文件中. 那没关系,只需在启动后从 wal 日志中重放日志做还原即可.
源码地址:https://github.com/etcd-io/etcd
数据恢复
入口函数:mian -> StartEtcd -> etcdserver.NewServer -> bootstrap
查看bootstrap
方法:
func bootstrap(cfg config.ServerConfig) (b *bootstrappedServer, err error) {
if cfg.MaxRequestBytes > recommendedMaxRequestBytes {
cfg.Logger.Warn(
"exceeded recommended request limit",
zap.Uint("max-request-bytes", cfg.MaxRequestBytes),
zap.String("max-request-size", humanize.Bytes(uint64(cfg.MaxRequestBytes))),
zap.Int("recommended-request-bytes", recommendedMaxRequestBytes),
zap.String("recommended-request-size", recommendedMaxRequestBytesString),
)
}
if terr := fileutil.TouchDirAll(cfg.Logger, cfg.DataDir); terr != nil {
return nil, fmt.Errorf("cannot access data directory: %v", terr)
}
if terr := fileutil.TouchDirAll(cfg.Logger, cfg.MemberDir()); terr != nil {
return nil, fmt