TiDB 多数派节点故障恢复指南
作者: 这里介绍不了我原文来源:https://tidb.net/blog/b72c3144
1. 背景
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-171-1716948228022.png)
(1) 我们所使用的 TiDB 目前采用 3 副本的部署方式,其中一份数据同时存储在多个节点中。然而,如果一个 Region 的多数或全部副本在短时间内全部下线,该 Region 将无法进行读写操作,对业务造成严重影响。
(2)在实际生产过程中,我们也曾遇到同一台交换机发生灾难性故障,如机房断电等情况,其下的多个 TIKV 宕机,也会造成多副本或全部副本丢失,导致业务不可用的情况。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-170-1716948383836.png)
(3)社区当前多数文章只针对某一个版本在该场景下进行了故障恢复。而在 V6.1.0 正式引入 Online Unsafe Recovery 功能,所以本文将整合 V6.1.0 版本及其之前和之后的两个版本在该场景下故障解决方案。
2. 原理介绍
对于 PD 来说,是如何获取某个 Region 的状态?
对于每个 Raft Group 的 Leader 和 PD 之间都存在心跳包,用于汇报这个 Region 的状态。心跳包中主要包括:
Leader 的位置
Followers 的位置
掉线副本的个数
数据写入 / 读取的速度
除此之外,PD 还会收集每个 TiKV 节点(Store)发送的心跳包。通过这两种心跳包得到的信息,PD 会通过一些策略来制定具体的调度计划。
而调度的基本操作大致分为:
增加一个副本(addReplica)
删除一个副本(RemoveReplica)
将 Leader 角色在一个 Raft Group 的不同副本之间进行迁移(TransferLeader)
假设我们现在有若干个 Region 分布在 5 个 Store 上,并且每个 Region 有 3 个副本,我们进行实验,手动挂掉 3 个 Store 。若剩余副本数等于 2,PD 可以通过调度进行 Leader 的重新选举以及副本的补充。但是若只剩余 1 个副本,那么就需要人工介入进行恢复。
3. 实验模拟
首先,使用 tiup-bench 工具来准备一些测试数据:
3.1 V6.1.0 以下版本(3 副本丢失 2 副本)
集群 store 情况:
这里用 IP+store id 代替真实 IP 地址。
Region 分布情况:
实验过程:
(1)集群正常状态
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-173-1716948783331.png)
所有表均可访问
(2)在 store 1 和 11 上 mv data 文件夹
移动后,store 1 和 11 两个 TiKV 节点状态变为 Disconnected。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-149-1716948906980.png)
(3)停止 store 1 和 11 的服务
这里要将 store 1 和 11 TiKV 服务不可用才能无法访问上述表。否则就会出现还能访问的情况。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-151-1716948930997.png)
TiKV 服务的配置文件一般在 /etc/systemd/system/tikv- 端口号.service 中。
需要将 Restart 置为 no,因为 Restart=always: 只要不是通过 systemctl stop 来停止服务,任何情况下都必须要重启服务。
再将 TiKV 进程 KIll 掉。
(4)访问对应表
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-152-1716949048328.png)
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-153-1716949060809.png)
符合我们的预期,3 副本状态下挂掉 2 个副本,访问 item 表不受影响,访问其他表会报错 : Region is unavailable。
(5)待修复 Region
核心原理在于使用单副本数据进行多副本补充,如下表所示:
所以我们需要在正常的 Store 上对副本进行补充:
在 Store 2 上修复 Region 34867、34879、34788 和 34776。
在 Store 3 上修复 Region 34780、34847、34743、34826 和 34830。
在 Store 10 上修复 Region 34764、34855、34839、34871 和 34875。
(6)开始修复
停止 TiKV 角色
关闭 PD 调度
修复 Region
这里使用 tikv-ctl 工具,需要到对应的 TiKV 节点去执行命令进行修复,如果是使用 TiUP 部署的集群,tikv-ctl 工具在 ~/.tiup/components/ctl/{VERSION}/ 目录下,拷贝到对应的 TiKV 节点(Store)上。
-s 是宕机的 TiKV 节点的 store id,-r 是我们要移除的 Region id(多个请以逗号分隔)。
Store 2:
Store 3:
Store 10:
执行成功会显示
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-154-1716949322844.png)
(7)启动集群,校验数据
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-175-1716949355745.png)
这里注意,store 1 和 11 是无法启动的,因为数据目录已经被 mv 了。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-174-1716949374509.png)
经过修复,上述表可以正常访问。
(8) 节点下线
最后可以将 store 4、7 对应的 TiKV 节点强制下线
3.2 V6.1.0 以上版本(3 副本丢失 2 副本)
在 V6.1.0 版本后,推出了在线有损恢复 Online Unsafe Recovery,现在,我们将使用这种方法进行故障恢复。
集群 store 情况:
| id | address || – | ——- || 1 | IP1 || 2 | IP2 || 3 | IP3 || 10 | IP10 || 11 | IP11 |
同上,这里用 IP+store id 代替真实 IP 地址。
Region 分布情况:
基于上述 Region 分布情况,假设我们关闭了 store 2 和 store 3 ,那么以下表将无法访问:district、item、new_order、order_line 和 stock。而不受影响的表包括:customer、history、orders 和 warehouse。
实验过程:
(1)集群正常状态
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-176-1716949523443.png)
所有表均可访问
(2)在 store 2 和 3 上 mv data 文件夹
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-177-1716949635998.png)
(3)访问表(在线有损恢复,不需要停止 store 2 和 3 的服务,这里要注意)
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-178-1716949676714.png)
(4)执行恢复命令
执行成功如下:
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-172-1716949712125.png)
(5)查看恢复进度
等待最后输出 "info": "Unsafe recovery Finished"
,即为恢复成功。
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-158-1716949831108.png)
经查询,上述表可以进行访问。
(6) 检查数据索引一致性
即使表进行正常读写,但不代表数据没有丢失。
"affected table ids: 40, 114, 137, 147, 152"
, 恢复完受影响的表 id,我们根据表 id 进行查询:
SELECT TABLE_SCHEMA, TABLE_NAME, TIDB_TABLE_ID FROM INFORMATION_SCHEMA.TABLES WHERE TIDB_TABLE_ID IN (40, 114, 137, 147, 152);
现在我们上述进行检查:
若有不一致的索引,通过以下步骤进行修复:
重命名索引:alter table 表名 rename 索引名 to 临时索引名
创建新索引:alter table 表名 add index 索引名 (列名)
删除旧索引:alter table 表名 drop index 临时索引名
(7) 宕机的节点下线
3.3 V6.1.0 以上版本 (3 副本全部丢失)
经过在线有损恢复后,使用的感受非常良好。现在我们思考,如果 3 个副本全部丢失,是否可以使用这种方式来恢复我们的数据?
接下来一起测试下。
老方法,我们首先使用 tiup-bench prepare 数据:
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-159-1716949963721.png)
集群 store 情况:
| id | address || – | ——- || 4 | IP2 || 1 | IP1 || 2 | IP7 || 10 | IP8 || 11 | IP9 |
Region 分布情况:
现在我们 mv 4,10,11 对应 TiKV 的 data 文件夹,并打开防火墙 (关闭和 pd 的通信) 以及中控机 tiup 的 ssh 端口模拟宕机。
之后观察报错情况:
leader 和 region 节点监控消失,store size 为丢失了 3 副本
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-160-1716950080867.png)
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-161-1716950135447.png)
业务异常,日志报错: “9005: Region is unavailable”
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-162-1716950161101.png)
server report failure 出现错误报告
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-163-1716950184475.png)
下面就到了激动人心的恢复时间了:
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-164-1716950212627.png)
最后一段输出信息:
查询结果:
![](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-165-1716950266801.png)
结果是,在三副本全部丢失的情况下,恢复成功了,这就比较令我感到诧异,随后团队将这个现象反应给了官方,也期待之后进一步完善。
4. 总结及思考
一般情况下,当 TiDB 集群发生故障后,只需进行重启即可完成多数派的选举,使集群能够正常对外提供服务。
然而,在极端情况下,例如 SST 文件损坏,就需要使用有损恢复的方式进行数据恢复。在这种情况下,恢复方案需要经过反复验证,以确保在线上的极端情况下能够成功完成数据恢复。
本文主要以 V6.1.0 为分界,针对 V6.1.0 版本及其之前和之后的两个版本,在 3 副本状态下多副本丢失的场景下进行故障模拟,并分别使用 tikv-ctl 手动恢复和在线有损恢复两种方式进行数据恢复。
值得注意的是,V6.1.0 之前的版本在线有损恢复功能为实验特性,因此对于小于 V6.1.0 的集群,我们可以考虑使用 tikv-ctl 手动恢复;而对于版本大于 V6.1.0 的集群,我们则可以考虑使用在线有损恢复方式。
同时,如果能够将恢复过程自动化,将极大地提高业务的稳定性。
版权声明: 本文为 InfoQ 作者【TiDB 社区干货传送门】的原创文章。
原文链接:【http://xie.infoq.cn/article/7ff9f015ce58ea377b97a2b5e】。文章转载请联系作者。
评论