TiDB 默认配置为 3 副本,每一个 Region 都会在集群中保存 3 份,它们之间通过 Raft 协议来选举 Leader 并同步数据。Raft 协议可以保证在数量小于副本数(注意,不是节点数)一半的节点挂掉或者隔离的情况下,仍然能够提供服务,并且不丢失任何数据。 对于 3 副本集群,挂掉一个节点除了可能会导致性能有抖动之外,可用性和正确性理论上不会受影响; 但是挂掉 2 个副本,一些 region 就会不可用,而且如果这 2 个副本无法完整地找回了,还存在永久丢失部分数据的可能。 这里主要讨论 2 个或 3 个副本丢失的问题。
在实际生产环境中,TiDB 集群是可能会出现丢失数据情况,如:
在上述这些情形下,会出现部分 Region 的多个副本(包含全部副本的情况)同时故障,进而导致 Region 的数据部分或全部丢失的问题。 这个时候,最重要的是快速地最大程度地恢复数据并恢复 TiDB 集群正常服务。
副本数据恢复包含两个部分:故障 Region 处理和丢失数据处理
故障 Region 处理步骤包括:处理前禁用 PD 调度、处理还有剩余副本的 Region、处理所有副本都丢失的 Region、处理后恢复 Region 调度。
pd-ctl config get
获取 region-schedule-limit、replica-schedule-limit、leader-schedule-limit、merge-schedule-limit
这 4 个参数的值,并记录下来用于后面恢复设置pd-ctl config set
将这 4 个参数设为 0使用 pd-ctl 检查大于等于一半副本数在故障节点上的 Region,并记录它们的 ID(假设故障节点为 1,4,5):
pd-ctl -u <endpoint> -d region --jq=’.regions[] | {id: .id, peer_stores: [.peers[].store_id] | select(length as $total | map(if .==(1,4,5) then . else empty end) | length>=$total-length) }’
根据上面的 Region 的个数,可以采取 2 种不同的解决方式(运行以下命令时需关闭相应 Store 上面的 TiKV):
tikv-ctl --db /path/to/tikv-data/db unsafe-recover remove-fail-stores -s <s1,s2> -r <r1,r2,r3>
tikv-ctl --db /path/to/tikv-data/db unsafe-recover remove-fail-stores -s <s1,s2> --all-regions
重启 PD,重启 TiKV 集群,使用 pd-ctl
检查没有 Leader 的 Region:
pd-ctl -u <endpoint> -d region --jq '.regions[]|select(has("leader")|not)|{id: .id, peer_stores: [.peers[].store_id]}'
创建空 Region 解决 Unavailable 报错。任选一个 Store,关闭上面的 TiKV,然后执行:
tikv-ctl --db /path/to/tikv-data/db recreate-region --pd <endpoint> -r <region_id>