在使用 etcd 作为配置存储或者其他的场景,如果因为误操作对其中 key 的值进行了修改,如果想要找回原来的值,可以利用 etcd 的版本机制进行回溯找回以前的值。在具体操作之前,我们首先获取一下 key 完整的信息来举个例子:

# 如果开启认证要指定 --user <username>:<password>
etcdctl get --endpoints=$ENDPOINTS <key> -w=json

上面 -w=json 是以 JSON 格式输出指定 key 的数据和元数据,例如下面的内容:

{"header":{"cluster_id":6783024485397960691,"member_id":2129759788194751561,"revision":583,"raft_term":5},"kvs":[{"key":"YWJjZA==","create_revision":370,"mod_revision":375,"version":4,"value":"NA=="}],"count":1}

我们首先看 header 里面的 revision 是当前 etcd 集群全局最新的版本号,注意这个版本号是当前存在数据的版本号,也就是最新写入键值的版本号,不是下一个版本号。然后 kvs 里面就是数据了,其中 key, value 都做了 Base64 编码,其中 create_revision 表示这个 key 创建时所对应的全局版本号,mod_revision 是表示当前版本的修订版本号,version 表示当前这个 key 的局部版本号,创建时的版本是 1,version 是 4 也就是说当前这个 key 在创建后修改了 3 次。

假如我们由于误操作而覆盖了这个 key 的值,那么可以就可以基于版本号来进行历史版本的回溯,前提是不能执行 compact,否则为了压缩空间所有的版本数据都会被清理掉,无法再进行恢复了。

然后如果没有合并过,我们就可以执行回溯,以上面的数据为例,创建版本为 370,修改版本为 375,那么我们要获得上一个版本,首先就需要拿 mod_revision - 1 去查询,然后就可以查询到上一个版本:

etcdctl get --endpoints=$ENDPOINTS <key> -w=json --rev=374

注意对于某个 key 来说,版本不是连续的,因为同时有其他 key 也在操作,这点要明白,现在我们拿到的信息如下:

{"header":{"cluster_id":6783024485397960691,"member_id":2129759788194751561,"revision":583,"raft_term":5},"kvs":[{"key":"YWJjZA==","create_revision":370,"mod_revision":373,"version":3,"value":"Mw=="}],"count":1}

可以看到上一个实际的版本是 373,然后我们再继续使用 372 获取:

etcdctl get --endpoints=$ENDPOINTS <key> -w=json --rev=372

结果如下:

{"header":{"cluster_id":6783024485397960691,"member_id":2129759788194751561,"revision":583,"raft_term":5},"kvs":[{"key":"YWJjZA==","create_revision":370,"mod_revision":371,"version":2,"value":"Mg=="}],"count":1}

可以看到上一个版本实际是 371,那么由于创建版本是 370,两者之间不可能再有其他版本号,所以到这里我们就得到了所有的版本号,当然在实际情况下也可能是不连续的,我们要迭代到两者相等为止,所以我们再继续查询一下:

etcdctl get --endpoints=$ENDPOINTS <key> -w=json --rev=370
{"header":{"cluster_id":6783024485397960691,"member_id":2129759788194751561,"revision":583,"raft_term":5},"kvs":[{"key":"YWJjZA==","create_revision":370,"mod_revision":370,"version":1,"value":"MQ=="}],"count":1}

毫无疑问,现在 create_revisionmod_revision 是相等的,那么也就意味着迭代完毕,拿到的版本号就是 370。

所以根据我们的迭代顺序,将版本号序列反转,结果为:370, 371, 373, 375,这样就得到的全部的版本号序列,然后我们就可以按照版本号依次查看 key 具体版本的值了:

# 只需要去掉 -w 选项,正常输出即可
etcdctl get --endpoints=$ENDPOINTS <key> --rev=<revision>

上面就是指定对于指定 key 整个回溯历史版本的过程,需要注意的是 etcd 只能根据全局的 revision 来回溯,不支持按照每个 key 的 version 来回溯,不过局部这个 version 可以用来直观地查看这个 key 被改了几次。

我们也可以根据上面的过程编写一个程序来实现快速查找 key 历史版本的功能,帮助我们快速拿到指定 key 的所有历史记录。

另外也可以使用 watch 的方法来拿到所有的历史记录,比如我们知道这个 key 对应的 create_revision,那么可以 watch 时指定初始版本,这样就会输出所有的历史:

etcdctl watch --endpoints=$ENDPOINTS <key> --rev=<create_revision>

这样就可以一次性拿到所有的修改记录,不过命令是阻塞的,需要手动结束,写程序时也需要做好控制。上面指定的版本号也不一定是 create_revision,指定个比较小的也可以,比如 1。

以上操作基于 etcd 3.5 版本。

基于 Rust 编写的 etcd 版本回溯工具:https://github.com/monchickey/etcd-version-history 可以参考使用。

Reference:

  1. https://etcd.io/docs/v3.5/learning/data_model/
  2. https://github.com/etcd-io/etcd/issues/7292
  3. https://github.com/etcd-io/etcd/issues/11027

etcd 历史版本回溯的方法的更多相关文章

  1. Oracle jdk 历史版本官方下载地址及下载方法

    Oracle jdk 历史版本官方下载地址及下载方法 原文转载至:http://blog.csdn.net/chwshuang/article/details/54925950 平时要新装一个系统环境 ...

  2. git操作记录(如何回退到某个历史版本,如何提交部分文件等方法)

    当前项目使用git管理代码,在使用的过程中会遇到一些问题,这里记录下 1.合并代码后 在合并组员的代码后会出现下面的界面,开始的时候都会关闭,重新打开,乐此不疲到忍无可忍 解决方法: 出现这种界面是要 ...

  3. Katalon Studio用迅雷快速下载历史版本方法

    一.下载说明 官网正版--历史版本下载地址: https://github.com/katalon-studio/katalon-studio/releases 说明1:这里需要注册账户才可以下载,但 ...

  4. 下载历史版本App超详细教程

    有些时候我们需要下载旧版本的 App 进行研究或者其他用途,然而在 iOS 下,苹果的 App Store 里面默认只能下载最新版本的 App,对滴,就是这么任性,不服不行.然而在 Android 里 ...

  5. C# 语言历史版本特性(C# 1.0到C# 8.0汇总)

    历史版本 C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有17年的历史,语言本身具有丰富的特性,微软对其更新支持也十分支持.微软将C#提交给标准组织ECMA,C# 5.0目前是ECM ...

  6. spring官网上下载历史版本的spring插件,springsource-tool-suite

    spring官网下载地址(https://spring.io/tools/sts/all),历史版本地址(https://spring.io/tools/sts/legacy). 注:历史版本下载的都 ...

  7. C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新)

    历史版本C#作为微软2000年以后.NET平台开发的当家语言,发展至今具有17年的历史,语言本身具有丰富的特性,微软对其更新支持也十分支持.微软将C#提交给标准组织ECMA,C# 5.0目前是ECMA ...

  8. homebrew 安装 formula 的不同历史版本——以安装 node 为例

    homebrew 安装 formula 的不同历史版本--以安装 node 为例 系统环境 macOS Mojave 10.14 Homebrew 1.8.0 Homebrew/homebrew-co ...

  9. 下载历史版本App

    文/timhbw(简书作者)原文链接:http://www.jianshu.com/p/edfed1b1822c著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 1.软件准备 [必备]C ...

  10. 奇技淫巧:在spring官网上下载历史版本的spring插件,springsource-tool-suite

    转自:https://blog.csdn.net/PacosonSWJTU/article/details/80959689 目前spring官网(http://spring.io/tools/sts ...

随机推荐

  1. RIPEMD算法:多功能哈希算法的瑰宝

    一.RIPEMD算法的起源与历程 RIPEMD(RACE Integrity Primitives Evaluation Message Digest)算法是由欧洲研究项目RACE发起,由Hans D ...

  2. 闭关修炼180天----吐血整理MongoDB的学习笔记

    MongoDB 一.MongoDB体系结构 1.1 mongoDB和NoSql mongoDB是一种NoSql,是文档存储的代表. mongoDB是一个基于分布式文件存储的数据库.为web应用提供可扩 ...

  3. MP实现ID自增 &日志 &自动填充 & 逻辑删除 &乐观锁

    默认ID自增 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl 此时的依赖 <dep ...

  4. gitee github 左侧栏树形显示插件 Octotree codetree 浏览器插件

    起因 看到一位仁兄用gitee做仓库 https://gitee.com/zhengqingya/java-developer-document 然后左侧栏挺方便(抖音视频) 下载 chrome扩展市 ...

  5. Vite + Vue3.0 项目初始化

    主要是冷启动,实际中项目非常庞大,现在1w的笔记本,每次冷启动,也得等一下,所以准备转型 Vite+Vue3.0,毕竟Vite不支持Vue2.0,这就只能下个项目的时候再启动了. $ npm init ...

  6. 恒玄科技BES250解决方案之双耳链接调试总结和源码分析

    一 前言 bes2500芯片在tws耳机应用十分广泛,该芯片有着资源强大,音质好,大厂背书等特色.吸引了不少粉丝跟随. 最近在调试该芯片的tws配对流程,花费了一些时间,踩了一些坑,这里做一个总结和备 ...

  7. 基于R语言的raster包读取遥感影像

      本文介绍基于R语言中的raster包,读取单张或批量读取多张栅格图像,并对栅格图像数据加以基本处理的方法. 1 包的安装与导入   首先,我们需要配置好对应的R语言包:前面也提到,我们这里选择基于 ...

  8. AHandler AMessage ALooper消息机制-源码6.0.0以上

    AHandler AMessage ALooper消息机制 AHandler是Android native层实现的一个异步消息机制,在这个机制中所有的处理都是异步的,将变量封装到一个消息AMessag ...

  9. 专访冠军考拉ok|“新人问我学Blender能找到工作吗,我回复不能”

    "新锐先锋,玩转未来"--首届实时染3D动画创作大赛由瑞云科技主办,英伟达.青椒云.3DCAT实时渲染云协办,戴尔科技集团.Reallusion.英迈.万生华态.D5渲染器.中视典 ...

  10. Anaconda 创建新环境

    使用conda 命令创建一个名为 python311 的python版本为3.11的环境 conda create -n python311 python=3.11 接着使用 conda activa ...