导读
要想搞定在线机房迁移之 TiDB 数据库迁移,看完本文基本上所有的迁移方案你都可以搞定了(数据库迁移方案和流程大同小异)。本文中 3 种 TiDB 在线迁移的场景和方案,大家可以根据各自的业务场景各取所需了。

一般在线机房迁移都是同城,且机房距离在 150 km,需要具备条件:
数据中心距离在 150 km 以内,通常位于同一个城市或两个相邻城市;
数据中心间的网络至少采用2条光纤专线连接,并且要求延迟 3 ms 左右,并且长期稳定运行;
双专线且带宽大于 200 Gbps。
物理机:比之前的配置要好,尤其当前的高密机型,考虑好硬盘 pv、cpu、内存资源规划;
K8s :版本选择,以及环境搭建完毕,到达可用程度,并且可以绑定物理机nodes 资源;
Operator:TiDB-operator 尽量选择高版本,做好调研和测试验证,到达可用状态。

在之前我写过的多云多活文章中有提及切换方案,并且基于线上的核心集群实施成功,相当于帮我们在线数据库迁移打好了坚实的基础。
因为知乎的 TiDB 是 all in K8s,我就先按照 K8s 给大家展示方案。
整体的迁移架构如上图所示,可以看到:
从结构上看,上方 K8s 集群 online 代表当前老机房的 TiDB 集群部署,里面包含了 TiDB 集群的各个组件。下方是新建立一套 k8s 集群,里面也部署了 TiDB 集群;
中间 2 个红框代表的同步链路,一个是基于 TiDB placement-rule 副本投放,从视图上还是同一套 TiDB 集群的迁移链路。另外一个是由 TiCDC 同步的上下游 2 套不同的 TiDB 集群(上下游的版本可以不一样)。
下面我们分别来聊下这两种迁移方案:
一、跨云跨 k8s 的 TiDB placement-rule 副本投放迁移(60% tidb 集群都由此方案迁移)
迁移架构说明

Placement Rules 是 PD 在 4.0 版本引入的一套副本规则系统,用于指导 PD 针对不同类型的数据生成对应的调度。通过组合不同的调度规则,用户可以精细地控制任何一段连续数据的副本数量、存放位置、主机类型、是否参与 Raft 投票、是否可以担任 Raft leader 等属性。Placement Rules 特性在 TiDB v5.0 及以上的版本中默认开启( 5.0 之前开启需要通过 pd-ctl 命令:config set enable-placement-rules true 开启)。默认开启 placement-rule 后的情况如下:
# ./pd-ctl -i
» config placement-rules show
[
{
"group_id": "pd",
"id": "default",
"start_key": "",
"end_key": "",
"role": "voter",
"is_witness": false,
"count": 5
}
注:"count": 5 副本是因为之前我 config set max-replicas 5 修改过集群副本量
如果我想给这个 TiDB 集群实现同城双中心的副本放置 3 个 voter 副本在老集群,2 个 follower 副本在新集群,并且在每个规则内通过 label_constraints 将副本限定在对应的数据中心内。配置如下:
[
{
"group_id": "pd",
"id": "default",
"start_key": "",
"end_key": "",
"role": "voter",
"count": 3,
"label_constraints": [
{"key": "zone", "op": "in", "values": ["zone1"]}
],
"location_labels": ["rack", "host"]
},
{
"group_id": "pd",
"id": "online2",
"start_key": "",
"end_key": "",
"role": "follower",
"count": 2,
"label_constraints": [
{"key": "zone", "op": "in", "values": ["zone2"]}
],
"location_labels": ["rack", "host"]
}
]
通过以上配置就搞定了新机房的副本投放,相当于我将之前 5 voter 副本都在 id=default 的老机房,拆分成了 3 个 voter 在老机房,2 个 follower 在新机房的同构集群。在 2 个 follower 副本数据同步完成后,修改 placement-rule 配置,将 id=online2 的 region role 由 follower 调整 voter 即可完成 region leader 的跨机房分布,通过观察监控等 leader 均衡后,调整老机房的 count=0,新机房的 count=5 来完成新机房的副本补充,一定时间后老机房 region 掉 0 就完全完成数据的迁移了。调整方式如下:
[
{
"group_id": "pd",
"id": "default",
"start_key": "",
"end_key": "",
"role": "voter",
"count": 0, ####这里的0就代表把老机房的副本删除了
"label_constraints": [
{"key": "zone", "op": "in", "values": ["zone1"]}
],
"location_labels": ["rack", "host"]
},
{
"group_id": "pd",
"id": "online2",
"start_key": "",
"end_key": "",
"role": "voter", ####这里将之前的follower调整到voter
"count": 5, ####这里的5就代表把新online2的副本扩容到5
"label_constraints": [
{"key": "zone", "op": "in", "values": ["zone2"]}
],
"location_labels": ["rack", "host"]
}
]
多云同构集群迁移操作步骤
pd-ctl member leader_priority <member_name> <priority>
kubectl exec tidb-test-0 -n tidb-test -- ./pd-ctl store |grep -B 2 'tidb-test.online2.com'|grep 'id":'|awk -F':' '{print $2}'|awk -F',' '{print "store limit "$1" 40 add-peer"}
如何观察?查看监控 region health(注意 miss-peer/extra-peer 的变化),另外还可以通过计算 leader region 数量 X 2 ,或者 store region数量 X store 量看估算。
注: Store Limit 与 PD 其他 xxxx-schedule-limit 相关的参数不同的是,Store Limit 限制的主要是 operator 的消费速度,而其他的 limit 主要是限制 operator 的产生速度。
config set leader-schedule-limit 16 ### 控制 Transfer Leader 调度的并发数
config set region-schedule-limit 2048 ### 控制增删 Peer 调度的并发数
config set replica-schedule-limit 64 ### 同时进行 replica 调度的任务个数
(5)均衡 region leader 到新机房集群(follower->voter)
上面讲方案时提到了 online2 机房的 tikv 如何通过 placement-rule 提升为 leader ,并且将老集群 region 缩 0 的方法。
需要考虑业务是否能接受跨机房读写 region leader 的延迟增加(从整个迁移周期来看,大部分都是接受的,影响可控),如果读写敏感业务,就需要定一个凌晨切全部的 leader 到 online2,以及切 PD leader 和业务域名到新机房。
(6)多云多活状态,缩容老机房所有 TiKV,delete store,对于“顽固 region ”进行 delete region
这种状态会持续一段时间,因为均衡 region leader,以及下线老机房的 region 都需要天级别的时间,对于下线老机房 store 时,会出现只剩下部分 region 无法迁移走的情况,这是需要用到强制删除的策略,下面的命令就是给 store id=10 的这个 tikv 强制增加 remove-peer 来删除老机房的 region:
kubectl exec tidb-test-pd-0 -n tidb-test -- ./pd-ctl region store 10| jq '.regions | .[]| "\(.id)"'|awk -F'"' '{print "kubectl exec tidb-test-pd-0 -n tidb-test -- ./pd-ctl operator add remove-peer ",$2," 10"}' > /home/daixiaolei/remove_peer.sh
(7)切 PD leader 到新机房
切 PD leader 时需要注意集群抖动和低峰切(我们曾经出现因百万region 切 PD leader 卡集群 1h,通过 pd-recover 修复的故障),因为之前设定了 leader_priority,需要进行调整,可以有两个方式切 PD leader:
直接设定 online2 的 pd leader_priority 比老机房高,这时PD集群就会因权重调整自动切PD。
设定online2的 pd leader_priority 跟老机房一致,手动并且选低峰执行 member leader transfer <member_name> 切主到 online2 的集群。
(8) 业务切读写到新机房
因为副本投放的集群两边机房访问的是同一个集群,所以只需要把 dns 从老机房迁到新机房即可,不用 kill 连接,待容器自动销毁后连接自动释放。
(9)缩容老机房 TiDB Server
缩容前查看 cluster-processlist 确认是否还有业务链接,如果有通过 pods IP 找到对应的业务程序,让业务及时切主。
查看监控是否还有业务流量,确认没有流量后,老机房 TiDB Server 缩 0。
(10) 老机房缩容所有 pd 节点
确认新 online2 机房有至少 3 个 pd 节点,就可以缩容老机房的所有 pd 节点。
(11) 老机房 delete pvc
默认缩容 TiKV 的 pods 的 PVC 不会删除,需要手动删除 PVC,这样 pv 也自然释放。
(12)老机房 delete tc
老机房 delete tc 的操作风险非常的巨大,操作错新 online2 机房的集群会有毁灭性的影响,操作时一定要 kubectl get pods -n tidb-test 看下是否是已经空的老集群,同时要找找 DBA double check 。
(13)回收物理机资源(delete nodes ,关机回收)
回收资源后,机房迁移完毕。
同构集群能够按照上述流程进行升级迁移,当你遇到无法副本投放的集群,就涉及到集群 tc.yaml 中的一个重要的配置 clusterDomain ,如果没有这个配置,就要创建异构集群来添加(所以对于 TiDB on K8s ,如果要跨 K8s 建立集群,必须要配置 clusterDomain )。
二、TiCDC 链接的主备集群( 30% TiDB 集群由此方案迁移)
优点
上下游都是独立集群,下游新集群的版本可以高于当前集群,对于需要替换的老 TiDB 版本或者希望用到新版本特性的业务可以迁移升级一并做了。但是一定要注意 TiDB 升级版本后的 SQL 兼容性。 对于之前多个核心数据库共用一套 TiDB 集群的拆分到多套集群,增加隔离和稳定性。 TiCDC 的迁移可以随时回滚,在业务停写切读写到下游集群时创建新集群到旧集群的反向同步任务,将新集群生产的数据同步回老集群,在业务确定迁移成功一周后再停掉同步任务,并删除老集群。
缺点
TiCDC 同步的延迟较高,对于读敏感业务,无法切读流量验证。 TiCDC 的同步能力有限制(单 worker 3w/s),对于线上写入 5w/s 的增量同步链路可能无法搭建 BR 备份/恢复大集群可能时间较长,需要调整 gc-life-time 来保证增量同步, gc-life-time 配置过长会保留较多 MVCC,可能会对 TiDB 读性能造成部分影响。
TiCDC 迁移操作步骤
(1)在 online2 创建新 TiDB 集群(根据业务要求,版本可以一样也可以升级到高版本);
(2)调整老集群的 gc_life_time ,比如设定为 3 天(72h,按需调整);
mysql> select * from mysql.tidb where VARIABLE_NAME like '%gc_life_time%';
+-------------------+----------------+----------------------------------------------------------------------------------------+
| VARIABLE_NAME | VARIABLE_VALUE | COMMENT |
+-------------------+----------------+----------------------------------------------------------------------------------------+
| tikv_gc_life_time | 10m | All versions within life time will not be collected by GC, at least 10m, in Go format. |
+-------------------+----------------+----------------------------------------------------------------------------------------+
1 row in set (0.02 sec)
mysql> update mysql.tidb set VARIABLE_VALUE='72h' where VARIABLE_NAME='tikv_gc_life_time';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from mysql.tidb where VARIABLE_NAME like '%gc_life_time%';
+-------------------+----------------+----------------------------------------------------------------------------------------+
| VARIABLE_NAME | VARIABLE_VALUE | COMMENT |
+-------------------+----------------+----------------------------------------------------------------------------------------+
| tikv_gc_life_time | 72h | All versions within life time will not be collected by GC, at least 10m, in Go format. |
+-------------------+----------------+----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
(3)使用 BR 工具备份老集群 databases 数据到 S3,BR 的版本要跟 TiDB 集群版本一致;
br backup db \
--pd "${PDIP}:2379" \
--db test \
--storage "s3://backup-data/db-test/2024-06-30/" \
--ratelimit 128 \
--log-file backuptable.log
(4)使用 BR 将 S3 的 TiDB 备份恢复到 online2 新集群;
br restore db \
--pd "${PDIP}:2379" \
--db "test" \
--ratelimit 128 \
--storage "s3://backup-data/db-test/2024-06-30/" \
--log-file restore_db.log
(5)创建老集群到新集群的 CDC 任务(老集群需要部署 CDC 组件),注意从备份日志中获取 TSO,这个 TSO 是 TiCDC 创建同步任务的依赖;
kubectl logs -f backup-tidb-test-backup-06301455-nv4pw -n tidb-test
./cdc cli changefeed create --pd=http://tidb-test-pd:2379 --sink-uri="tidb://test_wr:xxxx@tidb-test-peer.online2.com:4000/" --start-ts=434373684418314309 --config service_tree.toml --changefeed-id=tidb-test-migration
(6)同步验证:观察 grafana cdc 监控或者 cdc query changefeed-id 命令查看已经没有延迟,从数据量和 sample 抽样验证数据一致性;
(7)数据验证没问题,可以让读取不敏感的业务灰度读流量到新集群,验证业务 SQL 的执行情况;
(8)业务方读流量灰度 100% 到新集群就可以切写了,或者读写敏感型的选择凌晨低峰期切读写。业务切写的方式有两种选择:
空集群业务双写
BR/dumping 备份,业务切读切写

通过三个月的迁移,我们将几十套 TiDB 集群,总量 PB 级数据,通过以上各种方式,安全稳定的迁移到了新机房,在此期间,我们根据迁移方案,也开发了平台化的 DTS ,以及机房迁移模块跟进迁移进度。最后,感谢业务团队配合以及团队兄弟们的辛苦努力,共同达成此次在线机房迁移项目。














