Etcd数据恢复机制

这篇具有很好参考价值的文章主要介绍了Etcd数据恢复机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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.Errorf("cannot access member directory: %v", terr)
   }
   ss := bootstrapSnapshot(cfg)
   prt, err := rafthttp.NewRoundTripper(cfg.PeerTLSInfo, cfg.PeerDialTimeout())
   if err != nil {
      return nil, err
   }

   haveWAL := wal.Exist(cfg.WALDir())
   st := v2store.New(StoreClusterPrefix, StoreKeysPrefix)
   backend, err := bootstrapBackend(cfg, haveWAL, st, ss)
   if err != nil {
      return nil, err
   }
   var bwal *bootstrappedWAL

   if haveWAL {
      if err = fileutil.IsDirWriteable(cfg.WALDir()); err != nil {
         return nil, fmt.Errorf("cannot write to WAL directory: %v", err)
      }
      bwal = bootstrapWALFromSnapshot(cfg, backend.snapshot)
   }

   cluster, err := bootstrapCluster(cfg, bwal, prt)
   if err != nil {
      backend.Close()
      return nil, err
   }

   s, err := bootstrapStorage(cfg, st, backend, bwal, cluster)
   if err != nil {
      backend.Close()
      return nil, err
   }

   if err = cluster.Finalize(cfg, s); err != nil {
      backend.Close()
      return nil, err
   }
   raft := bootstrapRaft(cfg, cluster, s.wal)
   return &bootstrappedServer{
      prt: prt,
      ss: ss,
      storage: s,
      cluster: cluster,
      raft: raft,
   }, nil
}

上面代码逻辑大致如下 :

  • 检查数据目录是否可访问

  • 删除快照目录下的 tmp文件

  • 恢复最新快照数据

快照恢复

func recoverSnapshot(cfg config.ServerConfig, st v2store.Store, be backend.Backend, beExist bool, beHooks *serverstorage.BackendHooks, ci cindex.ConsistentIndexer, ss *snap.Snapshotter) (*raftpb.Snapshot, backend.Backend, error) {
   // Find a snapshot to start/restart a raft node
   walSnaps, err := wal.ValidSnapshotEntries(cfg.Logger, cfg.WALDir())
   if err != nil {
      return nil, be, err
   }
   // snapshot files can be orphaned if etcd crashes after writing them but before writing the corresponding
   // bwal log entries
   snapshot, err := ss.LoadNewestAvailable(walSnaps)
   if err != nil && !errors.Is(err, snap.ErrNoSnapshot) {
      return nil, be, err
   }

   if snapshot != nil {
      if err = st.Recovery(snapshot.Data); err != nil {
         cfg.Logger.Panic("failed to recover from snapshot", zap.Error(err))
      }

      if err = serverstorage.AssertNoV2StoreContent(cfg.Logger, st, cfg.V2Deprecation); err != nil {
         cfg.Logger.Error("illegal v2store content", zap.Error(err))
         return nil, be, err
      }

      cfg.Logger.Info(
         "recovered v2 store from snapshot",
         zap.Uint64("snapshot-index", snapshot.Metadata.Index),
         zap.String("snapshot-size", humanize.Bytes(uint64(snapshot.Size()))),
      )

      if be, err = serverstorage.RecoverSnapshotBackend(cfg, be, *snapshot, beExist, beHooks); err != nil {
         cfg.Logger.Panic("failed to recover v3 backend from snapshot", zap.Error(err))
      }
      // A snapshot db may have already been recovered, and the old db should have
      // already been closed in this case, so we should set the backend again.
      ci.SetBackend(be)

      s1, s2 := be.Size(), be.SizeInUse()
      cfg.Logger.Info(
         "recovered v3 backend from snapshot",
         zap.Int64("backend-size-bytes", s1),
         zap.String("backend-size", humanize.Bytes(uint64(s1))),
         zap.Int64("backend-size-in-use-bytes", s2),
         zap.String("backend-size-in-use", humanize.Bytes(uint64(s2))),
      )
      if beExist {
         // TODO: remove kvindex != 0 checking when we do not expect users to upgrade
         // etcd from pre-3.0 release.
         kvindex := ci.ConsistentIndex()
         if kvindex < snapshot.Metadata.Index {
            if kvindex != 0 {
               return nil, be, fmt.Errorf("database file (%v index %d) does not match with snapshot (index %d)", cfg.BackendPath(), kvindex, snapshot.Metadata.Index)
            }
            cfg.Logger.Warn(
               "consistent index was never saved",
               zap.Uint64("snapshot-index", snapshot.Metadata.Index),
            )
         }
      }
   } else {
      cfg.Logger.Info("No snapshot found. Recovering WAL from scratch!")
   }
   return snapshot, be, nil
}

上面代码逻辑大致如下:

  • 通过wal文件取出快照目录下的最新快照

  • 将最新快照数据加载到内存中:从快照数据中可以反序列化出:快照数据、对应的任期号、索引号

  • 检查内存快照数据是否合法

  • 使用最新快照恢复db数据

WAL恢复

// openWALFromSnapshot reads the WAL at the given snap and returns the wal, its latest HardState and cluster ID, and all entries that appear
// after the position of the given snap in the WAL.
// The snap must have been previously saved to the WAL, or this call will panic.
func openWALFromSnapshot(cfg config.ServerConfig, snapshot *raftpb.Snapshot) (*wal.WAL, *raftpb.HardState, []raftpb.Entry, *raftpb.Snapshot, *snapshotMetadata) {
   var walsnap walpb.Snapshot
   if snapshot != nil {
      walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
   }
   repaired := false
   for {
      w, err := wal.Open(cfg.Logger, cfg.WALDir(), walsnap)
      if err != nil {
         cfg.Logger.Fatal("failed to open WAL", zap.Error(err))
      }
      if cfg.UnsafeNoFsync {
         w.SetUnsafeNoFsync()
      }
      wmetadata, st, ents, err := w.ReadAll()
      if err != nil {
         w.Close()
         // we can only repair ErrUnexpectedEOF and we never repair twice.
         if repaired || !errors.Is(err, io.ErrUnexpectedEOF) {
            cfg.Logger.Fatal("failed to read WAL, cannot be repaired", zap.Error(err))
         }
         if !wal.Repair(cfg.Logger, cfg.WALDir()) {
            cfg.Logger.Fatal("failed to repair WAL", zap.Error(err))
         } else {
            cfg.Logger.Info("repaired WAL", zap.Error(err))
            repaired = true
         }
         continue
      }
      var metadata etcdserverpb.Metadata
      pbutil.MustUnmarshal(&amp;metadata, wmetadata)
      id := types.ID(metadata.NodeID)
      cid := types.ID(metadata.ClusterID)
      meta := &amp;snapshotMetadata{clusterID: cid, nodeID: id}
      return w, &amp;st, ents, snapshot, meta
   }
}

上面代码逻辑大致如下:

  • 根据上面拿到的快照数据,到wal目录中拿到日志索引号在快照数据索引号之后的日志,遍历满足条件的记录进行数据恢复。
    具体查看ReadAll方法文章来源地址https://www.toymoban.com/news/detail-497776.html

到了这里,关于Etcd数据恢复机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • XSAN数据恢复-存储空间架构迁移时误格式化存储系统的XSAN数据恢复案例

    XSAN数据恢复环境: 昆腾存储,MAC OS操作系统,存放视频类数据(MXF、MOV等格式文件)。 XSAN故障检测: 将存储空间从XSAN架构迁移到STORNEXT架构后,存储空间中数据全部丢失。  故障存储中一共有9个数据卷:1个META信息卷+8个DATA信息卷。北亚企安数据恢复工程师分析META信息卷

    2024年02月05日
    浏览(48)
  • 服务器数据恢复—Storwize V3700存储数据恢复案例

    服务器存储数据恢复环境: 某品牌Storwize V3700存储,10块硬盘组建了2组Mdisk加入到一个存储池中,一共创建了1个通用卷来存放数据,主要数据为oracle数据库。 服务器存储故障: 其中一组Mdisk中两块磁盘出现故障离线,该组Mdisk失效,导致该通用卷无法使用。 服务器存储数据恢

    2024年04月27日
    浏览(50)
  • 数据库数据恢复-Syabse数据库存储页底层数据杂乱的数据恢复案例

    数据库恢复环境: Sybase版本:SQL Anywhere 8.0。 数据库故障: 数据库所在的设备意外断电后,数据库无法启动。 错误提示: 使用Sybase Central连接后报错:     数据库故障分析: 经过北亚企安数据恢复工程师检测,定位到数据库无法启动的原因:突然断电导致Sybase数据库无法正

    2024年02月15日
    浏览(47)
  • 相机存储卡数据恢复怎么操作?数据恢复的图文教程来啦!

    喜欢拍照的朋友,看到美好的景物、人像等会忍不住按下拍照键,对于相机里面的照片也会非常珍视。但是时间久了,总会出现一些问题,比如相机存储卡里面的照片出现误删,或者格式化的情况,这是让人非常头痛的。 数据恢复该怎么操作? 我们还能把照片找回来吗? 来

    2024年02月08日
    浏览(53)
  • 【服务器数据恢复】HP MSA存储raid5数据恢复案例

    服务器故障环境: HP MSA某型号存储,8块SAS的硬盘组建RAID5磁盘阵列,其中包括1块热备盘。故障存储中基于该RAID组的LUN均分配给HP-Unix小机使用,上层做的LVM逻辑卷,存储的数据为Oracle数据库及OA服务端。 服务器故障: RAID5磁盘阵列中2块磁盘未知原因离线,阵列中的热备盘虽

    2023年04月26日
    浏览(53)
  • 服务器数据恢复—存储硬盘坏道,指示灯亮黄色的数据恢复案例

    服务器数据恢复环境故障: 一台某品牌EqualLogic PS系列某型号存储,存储中有一组由16块SAS硬盘组建的RAID5磁盘阵列,RAID5上划分VMFS文件系统存放虚拟机文件。存储系统上层一共分了4个卷。 raid5阵列中磁盘出现故障,有2块硬盘的指示灯显示黄色,存储不可用,存储设备已经过

    2024年04月26日
    浏览(44)
  • 服务器数据恢复-V7000存储2块磁盘故障脱机的数据恢复案例

    服务器数据恢复环境: P740+AIX+Sybase+V7000存储,存储阵列柜上共12块SAS机械硬盘(其中一块为热备盘)。 服务器故障: 存储阵列柜中有磁盘出现故障,工作人员发现后更换磁盘,新更换的磁盘数据同步到40%左右时,阵列柜中的另一块磁盘也出现问题,数据同步中断,逻辑盘无

    2024年02月07日
    浏览(45)
  • 服务器数据恢复—OceanStor存储raid5热备盘同步数据失败的数据恢复案例

    服务器数据恢复环境: 华为OceanStor某型号存储,存储内有一组由24块硬盘组建的raid5阵列,配置1块热备盘。 服务器故障: 该存储raid5阵列中有一块硬盘离线,热备盘自动激活并开始同步数据,在热备盘同步数据的过程中,raid5阵列中另一块硬盘离线,上层应用崩溃,数据丢失

    2024年01月19日
    浏览(60)
  • 相机存储卡被格式化了怎么恢复?数据恢复办法分享!

    随着时代的发展,相机被越来越多的用户所使用,这也意味着更多的用户面临着相机数据丢失的问题,很多用户在使用相机的过程中,都出现过不小心格式化相机存储卡的情况,里面的数据也将一并消失, 相机存储卡被格式化了怎么恢复 ?关于这个很多相机用户都疑惑的问

    2024年02月05日
    浏览(47)
  • 服务器数据恢复—EVA存储raid5硬盘离线的数据恢复案例

    服务器数据恢复环境: 某品牌EVA某型号存储,底层是RAID5阵列,划分了若干lun。 服务器故障分析: 该存储设备中raid5阵列有两块硬盘掉线,存储中的lun丢失。 将故障服务器存储中的所有磁盘编号后取出,硬件工程师检测后发现掉线硬盘不存在物理故障,也没有发现坏道,都

    2024年01月24日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包