etcd 数据管理

标签:etcd首次发布:2023-12-09最近修改:2026-08-16

etcd 数据存储

  • etcd 的存储分为内存存储持久化(硬盘)存储两部分。

  • 内存中的存储除了顺序化的记录下所有用户对节点数据变更的记录外,还会对用户数据进行索引、建堆等方便查询的操作。 而持久化则使用预写式日志(WAL:Write Ahead Log)进行记录存储。

  • 在 WAL 的体系中,所有的数据在提交之前都会进行日志记录。 在 etcd 的持久化存储目录中,有两个子目录。一个是WAL存储着所有事务的变化记录;另一个则是snapshot用于存储某一个时刻 etcd 所有目录的数据。通过 WAL 和 snapshot 相结合的方式,etcd 可以有效的进行数据存储和节点故障恢复等操作。

  • 既然有了 WAL 实时存储了所有的变更,为什么还需要 snapshot 呢?随着使用量的增加,WAL 存储的数据会暴增,为了防止磁盘很快就爆满,etcd 默认每 10000 条记录做一次 snapshot经过 snapshot 以后的 WAL 文件就可以删除。而通过 API 可以查询的历史 etcd 操作默认为 1000 条。

  • 首次启动时,etcd 会把启动的配置信息存储到 data-dir 参数指定的数据目录中。配置信息包括本地节点的 ID、集群 ID 和初始时集群信息。用户需要避免 etcd 从一个过期的数据目录中重新启动,因为使用过期的数据目录启动的节点会与集群中的其他节点产生不一致(如: 之前已经记录并同意 Leader 节点存储某个信息,重启后又向 Leader 节点申请这个信息)。所以,为了最大化集群的安全性,一旦有任何数据损坏或丢失的可能性,你就应该把这个节点从集群中移除,然后加入一个不带数据目录的新节点。

磁盘中存储的 snapshot 和 wal

bash
[root@centos default.etcd]# tree.└── member    ├── snap    │   └── db    └── wal        ├── 0000000000000000-0000000000000000.wal        └── 0.tmp3 directories, 3 files

灾难恢复

etcd 的灾难恢复主要依赖于备份和恢复机制。要执行灾难恢复,需要有一个最近的 etcd 数据快照,并且在必要时能够访问 WAL 日志文件。以下是灾难恢复的基本步骤:

  1. 备份

    定期备份是灾难恢复的关键。etcd 提供了快照功能来帮助你创建数据的全量备份。

    bash
    etcdctl snapshot save backup.db

    上述命令会创建当前 etcd 状态的快照,并将其保存到 backup.db 文件中。你可能还想要安全地存储 WAL 日志文件和配置文件,因为它们包含了重要的集群信息和更改历史。

  2. 恢复

    如果遇到了灾难性的事件,比如数据丢失或损坏,可以使用快照文件来恢复 etcd 集群。使用 etcdctl 的 snapshot restore 命令来从快照文件中恢复数据。

    bash
    etcdutl snapshot restore backup.db

    这个命令会从 backup.db 快照文件中读取数据,并初始化新的 etcd 数据目录。

注意事项:

  • 当从快照恢复时,etcd 会创建一个新的集群 ID。这意味着恢复的数据不能用于加入到原有的集群中,而是会形成一个新的集群。
  • 在恢复过程中,所有的数据将回滚到快照时的状态,这意味着在快照之后的所有数据更改都将丢失。

实践

现在我使用 docker 部署了有三个节点的 docker 集群,目录结构如下:

bash
[root@centos docker]# tree.├── etcd01│   └── member│       ├── snap│       │   └── db│       └── wal│           ├── 0000000000000000-0000000000000000.wal│           └── 0.tmp├── etcd02│   └── member│       ├── snap│       │   └── db│       └── wal│           ├── 0000000000000000-0000000000000000.wal│           └── 0.tmp└── etcd03    └── member        ├── snap        │   └── db        └── wal            ├── 0000000000000000-0000000000000000.wal            └── 0.tmp

在实际生成快照的过程中,可能会出现各种各样的问题。经过我各种失败的经验,最后能成功生成快照的命令是:

bash
docker exec -it -e ETCDCTL_ENDPOINTS=http://etcd-1:2379 etcd-1 etcdctl snapshot save /etcd-data/backup.db

结果如下所示:

bash
[root@centos docker]# docker exec -it -e ETCDCTL_ENDPOINTS=http://etcd-1:2379 etcd-1 etcdctl snapshot save /etcd-data/backup.db{"level":"info","ts":"2023-12-05T13:59:22.07852Z","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"/etcd-data/backup.db.part"}{"level":"info","ts":"2023-12-05T13:59:22.080236Z","logger":"client","caller":"v3@v3.5.10/maintenance.go:212","msg":"opened snapshot stream; downloading"}{"level":"info","ts":"2023-12-05T13:59:22.080285Z","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"http://etcd-1:2379"}{"level":"info","ts":"2023-12-05T13:59:22.081701Z","logger":"client","caller":"v3@v3.5.10/maintenance.go:220","msg":"completed snapshot read; closing"}{"level":"info","ts":"2023-12-05T13:59:22.082308Z","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"http://etcd-1:2379","size":"20 kB","took":"now"}{"level":"info","ts":"2023-12-05T13:59:22.082416Z","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"/etcd-data/backup.db"}Snapshot saved at /etcd-data/backup.db

这里有几点需要注意:

  1. 环境变量问题:由于我在使用 docker 创建容器的时候就设置了一个环境变量(–env ETCDCTL_ENDPOINTS=http://etcd-1:2379,http://etcd-2:2379,http://etcd-3:2379),又因为etcdctl snapshot save命令只能针对单个 etcd 节点执行快照操作,所以需要在执行命令之前,在同一行中设置环境变量的方式来覆盖容器中的环境变量,使用-e ETCDCTL_ENDPOINTS=http://etcd-1:2379将 etcdctl 的连接对象变成单个节点,这样就可以正确执行快照操作了。当整条命令执行完成后,使用 -e 选项设置的环境变量就会失效。
  2. 容器文件系统问题:刚开始我直接写了 backup.db 文件,但是执行完后我找不到 backup.db 文件在哪里,后来我发现整个命令是一个 docker 命令。对于 docker 命令,所有的文件路径都是相对于容器的文件系统的。所以需要做数据卷持久化将容器中的某个文件与宿主机进行同步。因为在创建容器的时候我已经指定了数据卷目录(–env ETCD_DATA_DIR=/etcd-data),所以需要将生成的 backup.db 文件放在 /etcd-data 目录下才能在宿主机中看到。

下面是备份文件的恢复:

使用 docker 部署 etcd 比较麻烦的地方就是做数据恢复,麻烦是因为:

  1. 当删除 etcd 的数据目录后运行 etcd 的容器会自动停止,一旦容器停止就无法进入容器内部使用 etcdutl 目录在数据恢复。
  2. 在做数据恢复的时候,etcd 的数据目录必需为一个空目录,不然无法恢复。

所以解决以上问题的思路就是:

  1. 首先在容器生成一个备份文件 backup.db,并可以在宿主机中拿到该备份文件(可以通过数据卷持久化完成)。
  2. 在宿主机中删除 member 目录,这样容器会自动停止。
  3. 用这个 backup.db 文件在宿主机中进行数据恢复,恢复完成后,会生成一个 member 目录。
  4. 将该 member 目录拷贝到数据卷持久化的那个目录,然后重新运行容器,数据就成功恢复了。

具体操作如下:

bash
# 备份文件在当前目录[root@centos etcd01]# ll总用量 24-rw-------. 1 root root 20512 12月  6 17:50 backup.db# 暂时移动到父目录,确保当前目录为空[root@centos etcd01]# mv backup.db ../[root@centos etcd01]# ll总用量 0# 进行数据恢复[root@centos etcd01]# etcdutl snapshot restore ../backup.db --data-dir=.2023-12-06T17:53:16+08:00	info	snapshot/v3_snapshot.go:260	restoring snapshot	{"path": "../backup.db", "wal-dir": "member/wal", "data-dir": ".", "snap-dir": "member/snap"}2023-12-06T17:53:16+08:00	info	membership/store.go:141	Trimming membership information from the backend...2023-12-06T17:53:16+08:00	info	membership/cluster.go:421	added member	{"cluster-id": "cdf818194e3a8c32", "local-member-id": "0", "added-peer-id": "8e9e05c52164694d", "added-peer-peer-urls": ["http://localhost:2380"]}2023-12-06T17:53:16+08:00	info	snapshot/v3_snapshot.go:287	restored snapshot	{"path": "../backup.db", "wal-dir": "member/wal", "data-dir": ".", "snap-dir": "member/snap"}[root@centos etcd01]# ll总用量 0drwx------. 4 root root 29 12月  6 17:53 member# 重启 etcd-1 容器[root@centos etcd01]# docker start etcd-1etcd-1[root@centos etcd01]# docker psCONTAINER ID   IMAGE                         COMMAND                   CREATED        STATUS         PORTS           NAMEScd8259ede541   quay.io/coreos/etcd:v3.5.10   "/usr/local/bin/etcd"    25 hours ago   Up 3 minutes   2379-2380/tcp   etcd-3f608fbd02cc0   quay.io/coreos/etcd:v3.5.10   "/usr/local/bin/etcd"    25 hours ago   Up 3 minutes   2379-2380/tcp   etcd-2ade7558c799a   quay.io/coreos/etcd:v3.5.10   "/usr/local/bin/etcd"    25 hours ago   Up 4 seconds   2379-2380/tcp   etcd-1# 之前的数据还在,说明恢复成功[root@centos etcd01]# docker exec -it etcd-1 etcdctl get namenamebing

Comments

评论区将在滚动到这里时加载。