TiKV 集群断电(灾难)恢复过程记录
作者: Timber 原文来源:https://tidb.net/blog/205fbb5f
背景
我们的应用使用 TiKV 作为存储层存储用户的数据。服务部署在用户的现场,现场遇到断电时,服务器文件经常会损坏,包括 TiKV 服务和 pd 服务的文件,本文整理了修复现场 TiKV 集群断电的过程,希望能起到参考作用。由于对 TiKV 的运维不熟悉,有些操作可能并不合理,欢迎大家在评论区指正。
环境
TiKV 版本 v6.1.0,TiKV 集群中包含 6 个 TiKV 节点,pd 正常。
修复过程
理论基础
在介绍修复过程之前,有必要对 TiKV 相关的一些概念进行说明。对 TiKV 架构熟悉的同学可以跳过。
TiKV 是存储数据的服务,当 sst 文件或 raftlog 损坏或丢失时,表示存储数据遭受损坏。当 TiKV 受损时,应尽可能减少数据的丢失,需要先使用工具对 TiKV 集群进行修复,如果修复无效,可以使用 unsafe 方式进行恢复。unsafe 方式是在 TiKV 大多数 sst 文件受损时从其他 TiKV 节点恢复数据的方法,期间会删除本机 TiKV 数据,可能会出现数据丢失的情况,使用时需要慎重!
TiKV 内部存储的逻辑单元是 Region,对应了一段 key range。而底层实际存储数据的物理单元是 rocksDB 的 sst 文件,一个 region 可能存储在多个 sst 文件内,一个 sst 文件内也可能包含了多个 region 的信息。当 sst 文件损坏时,除了修复 sst 文件之外,还需要修复 pd 维护的 region 信息。因此:当 TiKV 集群恢复成功后,region 状态可能并不完整,还需要对 region 进行修复。
大致修复思路
pd 维护了集群的元数据,TiKV 的恢复可能会用到 pd 的元信息以及 pd 的工具。因此,在 TiKV 集群遭遇断电时,应该先查看 pd 集群是否正常运行,如果有 pd 节点无法正常启动,优先处理 pd 节点。当 pd 集群恢复正常后,恢复 TiKV 节点。TiKV 节点均启动后,通过 pd 修复受损的 region。
排查现场情况
3 台 TiKV 无法正常重启,可能已经丢失了数据。
一台重启报错 invalid configuration: Found raft data set when it should not exist. 提示 raft 数据不应该存在,为方便描述,假设该实例为 TiKV-1
一台报错为[ERROR] [engine_factory.rs:156] [“failed to create kv engine”] [err=“Engine(\“Corruption: Can’t access /2103071.sst: IO error: No such file or directorywhile stat a file for size: /data/db/2103071.sst: No such file or directory,提示 sst 数据丢失,设为 TiKV-2
一台报错为[FATAL] [server.rs:1487] [“failed to create kv engine: Storage Engine Corruption: Sst file size mismatch: /data/db/2123787.sst. Size recorded in manifest 27100810, actual size 36721252\n”],提示 sst 文件损坏,设为 TiKV-3
当时我看到三台 TiKV 同时无法重启且报错均不相同,心情大概是这样的:
修复过程
柿子先捏软的,应该尽可能修复容易修复的 TiKV,这样,即使其他的无法修复了,还可以用到后续的 unsafe 方式从正常节点上恢复数据。
修复 TiKV-1.raftlog 损坏,这个报错比较奇怪,Found raft data set when it should not exist. 我们设置的 log 确实是使用的 raft-engine,但却提示不应该存在。修复步骤为:
备份 raft-engine 目录. 在服务器上删除该目录,重启 tikv 实例。这时会报错端口冲突 [FATAL] [server.rs:950] [“failed to start node: Grpc(RpcFailure(RpcStatus { code: 2-UNKNOWN, message: \“duplicated store address: id:67387001 address:\\\“xxxxxx:17515\\\” version:\\\“6.1.0 , already registered by id:29694712 address:\\\“xxxxxx:17515。 从报错中可以看到,id 为 67387001 的端口被 29694712 这个 id 注册过了。原因是,每个 TiKV 实例都是一个 store,每个 store 都有一个 id,这个 id 在 pd 中维护,pd 只认识原先的 store id,需要在 pd 维护的信息中删除原先的 id,新起的 store id 才能注册到 pd 中。在报错例子中,应该删除的 id 是 29694712。
随机找一个 pd 实例,进入到容器中,执行./pd-ctl store 查看 store 状态,store 状态中记录了每个 tikv 实例的 store id、store 状态、地址等信息。通过失效 tikv 的地址找到其 store_id,再通过./pd-ctl store delete {tikv-store_id} 删除原来的 store-id。重启 tikv 成功,再查看 pd-ctl store 结果,新的 store-id(例如 b 中的 67387001)出现在了输出结果中。
修复 TiKV-3,sst 数据损坏。为啥先修 sst 数据损坏呢,损坏的至少还有可能抢救,丢失的是真无法抢救了。修复步骤:
停止 TiKV-3,避免自动重启
修复 sst 文件需要用到 TiKV 的官方修复工具 tikv-ctl,TiKV 镜像中自带了该工具,也可以通过 安装 TiUP 来使用 tiup 集成的 tikv-ctl。实践时通过跑 TiKV 容器,挂载了 tikv 目录,并在容器中执行。
先执行./tikv-ctl ldb –db=data/db repair,该命令会修复 db 目录下的所有 sst 文件。
等待 repair 完成后,重启 tikv 实例,重启成功说明修复 sst 文件成功。
ps:本来打算用另外一种简单的方式恢复的,unsafe 方式,该方式可以忽略损坏的 sst 和 region 强行拉起 tikv,但是并未成功,这里也分享一下:
/tikv-ctl –data-dir /data bad-ssts –pd <pd_endpoint>
该工具会检测出该 TiKV 实例上的所有损坏的 sst 文件,移除这些 sst 文件,并且从 pd 中找到该文件相关的 region,将该 TiKV Store 上的 region 设置为 tombstone 以便让该 TiKV 实例在启动时跳过这些 region。但在执行过程中,由于 pd 会隔一段时间自动重启(v6.1.0 的 bug,详见https://github.com/tikv/pd/issues/6647#event-9629298440 ,v6.3.0 已经修复 ),该命令不会顺利执行。
工具输出结果实例如下,按照 suggested operations 执行命令即可。suggested operations 是工具提供的建议命令,第一行表示删除 sst 文件,第二行表示将该实例上的受损 region 设置为 tombstone。如果设置 tombstone 失败,可以加上 –force 选项重试。
修复 TiKV-2,sst 文件丢失。由于 sst 文件丢失了,我选择了直接 unsafe remove-failed-store,并直接删除了该 store 上的所有数据,重建了该节点,选择从其他节点上恢复数据。这种方式可能会丢失数据。因此,在进行 unsafe remove TiKV 之前,需要尽可能先修复其他比较容易恢复的 TiKV 节点,减少数据丢失。
查看损坏 TiKV 节点的 store id。随机进入一台 pd 的容器,执行./pd-ctl store,查看当前 TiKV 集群节点的状态。找到状态为 Disconnected(有可能是 Down 状态)的 store id。
使用 pd-ctl unsafe recover 恢复。下面命令中,首先移除了丢失的 TiKV 节点 4(在上一步骤中得到),如果需要移除多个节点,需要用逗号隔开,如 remove-failed-stores 4, 5。其中的地址是 pd 节点的 ip,端口为启动参数中的 –advertise-client-urls
| | | ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————– | |
/ # ./pd-ctl -u
{pd_addr}unsafe remove-failed-stores 4
Success!
/ # ./pd-ctl -u
{pd_addr}unsafe remove-failed-stores show
[
{
"info": "Unsafe recovery enters collect report stage: failed stores 4",
"time": "2023-06-05 07:35:47.195"
},
{
"info": "Unsafe recovery finished",
"time": "2023-06-05 07:35:56.182"
}
]
|使用 remove-failed-stores show 命令查看进度,等到出现 Unsafe recover finished 时,表示移除成功。
此时 TiKV 节点下线,剩余节点能重新调度并提供服务。
停止失效的 TiKV 节点,删除 TiKV 的所有数据,重启即可,重启后的新节点将从其他正常 TiKV 上恢复数据
至此,TiKV 节点总算是都修复完成了。但是任务还没有完成,我们的应用无法正常运行,报错 CDC:ErrRegionsNotCoverSpan]regions not completely left cover span,表示 tikv 的 regions 无法满足我们应用要拉取的范围。这是因为虽然 TiKV 启动成功了,但是修复过程中可能导致 region 的失效,或者说有些 region 本身就丢失了,集群无法正常使用这些 region 提供服务,需要对 region 进行进一步恢复。
有些 region 虽然已经失效了,但是可以通过重建的方式把 region 的逻辑拉起来,即使数据已经丢失,但在外部看起来,region 是没有丢失的。恢复步骤:
随机选择一个 pd 节点,进入到容器中,执行./pd-ctl region 查看集群中所有 region 的信息。region 信息中包含一项为 ”leader”,找到所有 leader 为[]或者缺乏 leader 项的 region
需要重建上述步骤中找到的所有缺乏 leader 的 region。选择一台 TiKV,关闭实例,在其所在的服务器上,运行 tikv 容器并在容器中执行./tikv-ctl –data-dir /data –config=/tikv.toml recreate-region -p {PD_ADDR} -r {region_id},必要时可以通过脚本批量重建 region
脚本执行成功后,重启 TiKV 实例。
work out,至此,TiKV 集群能正常提供服务且我们的应用依赖存储的逻辑能正常运行。
版权声明: 本文为 InfoQ 作者【TiDB 社区干货传送门】的原创文章。
原文链接:【http://xie.infoq.cn/article/6d3b8044e55eabb415c78e051】。文章转载请联系作者。
评论