1 PD是什么
PD (Placement Driver) Server:整个 TiDB 集群的元信息管理模块,负责存储每个 TiKV 节点实时的数据分布情况和集群的整体拓扑结构,提供 TiDB Dashboard 管控界面,并为分布式事务分配事务 ID。PD 不仅存储元信息,同时还会根据 TiKV 节点实时上报的数据分布状态,下发数据调度命令给具体的 TiKV 节点,可以说是整个集群的“大脑”。此外,PD 本身也是由至少 3 个节点构成,拥有高可用的能力。
PD大体来讲基本上就是一个etcd集群那么etcd又是什么呢?
2 etcd又是什么
etcd是一个非常可靠的kv存储系统,常在分布式系统中存储着关键的数据。它是由coreos团队开发并开源的分布式键值存储系统,具备以下特点:
- 简单:提供定义明确且面向用户的API
- 安全:支持SSL证书验证
- 性能:基准压测支持1w+/sec写入
- 可靠:采用Raft协议保证分布式系统数据的可用性和一致性。
etcd的这些特性,使得它常常出现在分布式设计场景下的工具集中。etcd在工作时也需要选举leader作为整个集群的信息发布与接收者,所以如果etcd集群在发生大于半数节点宕机的时候也会发生故障。
下文是一个关于恢复PD多节点宕机的一个场景测试。
3 首先看一下集群的初始状态
4开始我们的恢复
1 数据没了,脑子还清晰
这里我模拟的数pd节点所有数据文件全部损坏的场景,对于一个节点或者两个节点损坏的情况相信大家看过这篇文章之后就都可以搞定了,大体的战术都是一样的。
[root@localhost ~]# rm -rf /tidb-data/pd-4379/* [root@localhost ~]# rm -rf /tidb-data/pd-2379/* [root@localhost ~]# rm -rf /tidb-data/pd-3379/*
经过一段短暂的时间之后可以看到2379节点当期选为了新的leader,因为虽然三个节点数据文件都删除了但是三个节点都存活着,可以满足多数派的选举。但是其实我们还是可以看到日志中仍然是有问题的,我们display看一下
这里可以看到虽然pd节点看似正常,但是我们的tikv\tidb\tiflash都宕机了,看一下tikv的日志。
这里提示 please reconnect to the correct PD 由于之前三个节点数据文件全部删除,pd节点进行了重启并重新选举,造成了集群的id的改变,所以这里tikv就不认识了,针对这个情况我们需要做一下恢复
\[2022/03/28 13:26:38.294 +08:00] \[FATAL] \[server.rs:762] \["failed to bootstrap node id: \\"\[src/server/node.rs:253]: cluster ID mismatch, local 7077933617752007932 != remote 7080007299650314190, you are trying to connect to another cluster, please reconnect to the correct PD\\""]
这里clusterid我们可以从tikv的日志中获取 local 7077933617752007932 != remote 7080007299650314190
alloc-id我们可已从pd节点的日志中获取可以用下边的命令,我们需要选取三个节点中最大的id:
[root@localhost /]# cat /tidb-deploy/pd-4379/log/pd.log |grep "idAllocator allocates a new id" | awk -F'=' '{print $2}' | awk -F']' '{print $1}' | sort -r | head -n 1
找到alloic-id之后再加上上边的clusterid就可以开始恢复了
[tidb@localhost ~]$ tiup pd-recover -endpoints http://192.168.135.148:2379 -cluster-id 7077933617752007932 --alloc-id=16000
恢复之后重启一下pd集群我们就可以看到一切恢复正常了。
2 数据没了,脑子也坏掉了
其实上边的场景还是比较乐观的,虽然三个节点都出了问题但是还能保证集群的leader选举,下边这个场景就比较烦了,因为它”脑裂”了。如下如所示,pd节点出现了两个leader,就说明它”脑裂”了。针对这种情况我们就不能直接恢复了。首先要让他变成唯一一个leader才可以。
脑裂是什么?
在HA集群系统中,假设有同一个整体、动作协调的节点A 和节点B,节点A和B之间通过heartBeat来检查对方的存活状态,负责协调保证整个集群服务的可用性。正常情况下,如果节点A通过心跳检测不到B的存在的时候,就会接管B的资源,同理节点B检查不到B的存活状态的时候也会接管A的资源。如果出现网络故障,就会导致A和B同时检查不到对方的存活状态认为对方出现异常,这个时候就会导致A接管B的资源,B也会接管A的资源。原来被一个节点访问的资源就会出现被多个节点同时访问的情况,这种情况就是脑裂现象。
这里我的思路就是先把所有的pd节点都停掉,然后选择一个节点作为leader然后让他起来。我们手动修改一个节点的pdservice文件,我们把initial-cluster字段只留有一个节点的信息,这样让pd以单节点模式启动,那么他必然就只有一个leader了。
[root@localhost ~]# cat /tidb-deploy/pd-3379/scripts/run_pd.sh
--initial-cluster="pd-192.168.135.148-3379=[http://192.168.135.148:3380](http://192.168.135.148:2380/)"
通过service启动pd
[root@localhost ~]# systemctl restart pd-3379.service
pd启动后 tikv\tidb\tiflash还是DOWN的状态这个是正常的,因为 我们重启了pd以单节点启动之后pd的集群id必然发生了改变,我们只需要像上边那样在继续做恢复就可以了。这里需要注意的就是,一定不要把哪两个又问题的节点启动,始终我们都是手动启动pd节点,保证始终只有一个pd节点。
[tidb@localhost ~]$ tiup pd-recover -endpoints http://192.168.135.148:3379 -cluster-id 7077933617752007932 --alloc-id=20000
[root@localhost ~]# systemctl restart pd-3379
下图这样就基本ok了,我们要做的就是缩容有问题的两个pd节点,在扩容就好了,详细的步骤这里就不多写了。大家可以参考官方文档的扩容缩容就可以了。
[tidb@localhost ~]$ tiup cluster scale-in tidb-jiantest --node 192.168.135.148:3379 --force
[tidb@localhost ~]$ tiup cluster scale-in tidb-jiantest --node 192.168.135.148:2379 --force
[tidb@localhost ~]$ tiup cluster scale-out tidb-jiantest scaleout-pd.yaml
好了,这样就一切正常了。
5 总结
对于PD节点恢复,其核心就是要保证leader的唯一性和多数派选举的问题。至于PD中存放的数据还不是那么的紧张,因为当PD恢复正常后,tikv节点会自动向pd节点推送集群的信息。
- 如果只有一个节点的pd损坏那么我们只要将这个节点scale-in然后在scale-out就可以了,因为剩下的两个节点仍然可以满组多数派,但是还是要尽快补足,满足基数节点以免发生偶数节点脑裂的问题。
- 如果大于半数的pd节点损坏,我们可以直接参照节点全部损坏的场景去做,或者按照脑裂的方式都是可以的,因为大于半数节点损坏之后集群就无法选出leader了,或者也可以按照脑裂的样例单独启动一个节点再对其他的节点进行缩容扩容处理。
- pd节点只是存储集群的metadata,并且这些信息是由tikv等节点进行主动推送,所以当pd节点的所有数据丢失后,可以通过重建pd进行恢复而不必担心pd的数据问题,但是这里也有特例如果使用的TICDC等组件,那么changefeed等配置信息就需要重新创建了,因为这些信息是由我们手动创建的。
- pd恢复后关于PD本身的有一些参数就会变成默认值比如调度参数等这些也会需要我们手动进行设置。