背景
因降本的原因,需要将流量较小的 TiDB 集群下线,并将其数据合并到新的 TiDB 集群。
schema | version |
---|---|
上游 TiDB 集群 | v5.4.0 |
下游 TiDB 集群 | v5.4.3 |
此次合并集群用的工具有:
dumpling 导出 + loader 导入 + TiCDC 增量数据实时同步;
TiCDC 数据同步原理可参考TiCDC 架构和数据同步链路解析 。
第 1 步:搭建环境
1、部署上下游 TiDB 集群,分别扩容 TiCDC 节点。
编写 vim scale-out-ticdc.yaml
文件:
cdc_servers:
- host: 10.1.1.1
gc-ttl: 86400
data_dir: /data04/deploy/install/data/cdc-8300
- host: 10.1.1.2
gc-ttl: 86400
data_dir: /data04/deploy/install/data/cdc-8300
运行扩容命令:
tiup cluster scale-out prod-tidb-004 /home/tidb/prod-tidb-004/scale-out-ticdc.yaml
2、查看集群拓扑,确认上下游集群 TiCDC 节点都已经扩容完成。
tiup cluster display prod-tidb-004
Cluster name: prod-tidb-004
Cluster version: v5.4.2
......
10.1.1.1:8300 cdc 10.1.1.1 8300 linux/x86_64 Up /data04/deploy/install/data/cdc-8300 /data/tidb-deploy/cdc-8300
10.1.1.2:8300 cdc 10.1.1.2 8300 linux/x86_64 Up /data04/deploy/install/data/cdc-8300 /data/tidb-deploy/cdc-8300
......
第 2 步:迁移全量数据
1、关闭 GC。
SELECT @@global.tidb_gc_enable;
SET GLOBAL tidb_gc_enable=false;
SELECT @@global.tidb_gc_enable;
2、备份数据。
使用 Dumpling 工具导出上游集群多个库的全量数据。
cd /data01/tidb-toolkit-v5.2.2-linux-amd64/bin/
./dumpling -u dba -p passwd -h 10.1.1.xx -P 4000 -F 64MiB -t 4 -B db1,db2,db3,db4 --params "tidb_distsql_scan_concurrency=5,tidb_mem_quota_query=8589934592" -o /data01/tidb_backup/migrate_to_prod004_4db/
2.1、导出完毕后,查看备份文件,确认多个库均已导出完成。
2.2、查看备份的点位, 执行如下命令查看导出数据的元信息,metadata 文件中的 Pos 就是导出快照的 TSO,将其记录为 BackupTS:
cat metadata
Started dump at: 2022-10-12 17:25:15
SHOW MASTER STATUS:
Log: tidb-binlog
Pos: 436618321009573893
GTID:
Finished dump at: 2022-10-12 17:35:14
3、恢复数据。
使用 Loader 将 Dumpling 导出的上游全量数据导入到下游 TiDB 实例:
cd /data01/tidb-enterprise-tools-nightly-linux-amd64/bin
./loader -u dba -p 'passwd' -h 10.1.1.xx -P 4002 -t 2 -d /data01/tidb_backup/migrate_to_prod004_4db/
loader
可以断点续传真是太棒了!
遇到上下游TiDB版本不一致导致表结构导入有报错时,方便统一表结构后再次导入下游。
这里也可以采用 TiDB Lightning 工具做导入(
TiDB v5.3.0
及以上可使用),为避免影响下游可使用TiDB-backend
模式(配置文件中设置backend = "tidb"
)。
第 3 步:迁移增量数据
1、创建 CDC 同步任务。
【编写配置文件】:
cd /home/tidb/ticdc
vim migrate_to_prod004_ticdc_config.toml
#cat migrate_to_prod004_4db_ticdc_config.toml
# 指定配置文件中涉及的库名、表名是否为大小写敏感
# 该配置会同时影响 filter 和 sink 相关配置,默认为 true
case-sensitive = true
# 是否输出 old value,从 v4.0.5 开始支持,从 v5.0 开始默认为 true
enable-old-value = true
[filter]
# 过滤器规则
# 过滤规则语法:https://docs.pingcap.com/zh/tidb/stable/table-filter#表库过滤语法
rules = ['db1.*', 'db2.*', 'db3.*', 'db4.*']
[mounter]
# mounter 线程数,用于解码 TiKV 输出的数据
worker-num = 8
【创建任务】:
tiup ctl:v5.4.0 cdc changefeed create --pd=http://10.1.xx.xx:2379 --sink-uri="mysql://dba:passwd@10.1.xx.xx:4000/?worker-count=16&max-txn-row=5000&time-zone=Asia/Shanghai" --changefeed-id="task-migrate-to-prod004" --sort-engine="unified" --start-ts=436612662618488841 --config /home/tidb/ticdc/migrate_to_prod004_ticdc_config.toml
以上命令中:
--pd
:实际的上游集群的地址--sink-uri
:同步任务下游的地址--changefeed-id
:同步任务的 ID,格式需要符合正则表达式^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$
--start-ts
:TiCDC 同步的起点,需要设置为实际的备份时间点,也就是第 2 步:迁移全量数据中 “备份数据” 提到的 BackupTS
更多关于 changefeed 的配置,可以参考官网【同步任务配置文件】。
【查看 TiCDC 同步任务的状态】:
$ tiup ctl:v5.4.0 cdc changefeed list --pd=http://10.1.xx.xx:2379
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v5.4.0/ctl cdc changefeed list --pd=http://10.1.xx.xx:2379
[
{
"id": "task-migrate-to-prod004",
"summary": {
"state": "normal",
"tso": 436641144642469889,
"checkpoint": "2022-10-13 17:36:20.527",
"error": null
}
}
]
checkpoint
:==即为 TiCDC 已经将该时间点前的数据同步到了下游==。state
为该同步任务的状态:normal
:正常同步。stopped
:停止同步(手动暂停或出错)。removed
:已删除任务。
2、上游重新开启 GC。
SELECT @@global.tidb_gc_enable;
SET GLOBAL tidb_gc_enable=TRUE;
SELECT @@global.tidb_gc_enable;
3、查看 TiCDC 任务状态
【查看指定的任务】:
tiup ctl:v5.4.0 cdc changefeed query -s --pd=http:10.1.xx.xx:2379 --changefeed-id=task-migrate-to-prod004
【查看任务详细信息】:
tiup ctl:v5.4.0 cdc changefeed query --pd=http://10.1.xx.xx:2379 -c task-migrate-to-prod004
Starting component `ctl`: /home/tidb/.tiup/components/ctl/v5.4.0/ctl cdc changefeed query --pd=http://10.1.xx.xx:2379 -c task-migrate-to-prod004
{
"info": {
"sink-uri": "mysql://dba:passwd@10.1.xx.xx:4002/",
"opts": {
"_changefeed_id": "sink-verify"
},
"create-time": "2022-10-13T16:28:29.526804276+08:00",
"start-ts": 436639195916664835,
"target-ts": 0,
"admin-job-type": 0,
"sort-engine": "unified",
"sort-dir": "",
"config": {
"case-sensitive": true,
"enable-old-value": true,
"force-replicate": false,
"check-gc-safe-point": true,
"filter": {
"rules": [
"db1.*",
"db2.*",
"db3.*",
"db4.*"
],
"ignore-txn-start-ts": null
},
"mounter": {
"worker-num": 8
},
"sink": {
"dispatchers": null,
"protocol": "",
"column-selectors": null
},
"cyclic-replication": {
"enable": false,
"replica-id": 0,
"filter-replica-ids": null,
"id-buckets": 0,
"sync-ddl": false
},
"scheduler": {
"type": "table-number",
"polling-time": -1
},
"consistent": {
"level": "none",
"max-log-size": 64,
"flush-interval": 1000,
"storage": ""
}
},
"state": "normal",
"error": null,
"sync-point-enabled": false,
"sync-point-interval": 600000000000,
"creator-version": "v5.4.0"
},
"status": {
"resolved-ts": 436641687359455233,
"checkpoint-ts": 436641687044882437,
"admin-job-type": 0
},
"count": 0,
"task-status": [
{
"capture-id": "3786de8d-b1e4-40f8-927c-88e2e56665f5",
"status": {
"tables": {
"311": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"333": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"346": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"348": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"363": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"366": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"423": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"427": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"429": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"431": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"446": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"448": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"450": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"456": {
"start-ts": 436640265844293633,
"mark-table-id": 0
}
},
"operation": {},
"admin-job-type": 0
}
},
{
"capture-id": "5df19b4c-e31d-4f81-a757-95551b1cd3c2",
"status": {
"tables": {
"335": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"350": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"354": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"356": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"373": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"383": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"421": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"425": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"433": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"435": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"437": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"444": {
"start-ts": 436640265844293633,
"mark-table-id": 0
},
"458": {
"start-ts": 436640265844293633,
"mark-table-id": 0
}
},
"operation": {},
"admin-job-type": 0
}
}
]
}
【暂停任务】:
tiup ctl:v5.4.0 cdc changefeed pause --pd=http://10.1.xx.xx:23799 --changefeed-id=task-migrate-to-prod004
#然后确认"state": "stopped"
tiup ctl:v5.4.0 cdc changefeed query --pd=http://10.1.xx.xx:2379 --changefeed-id=task-migrate-to-prod004
【恢复任务】:
tiup ctl:v5.4.0 cdc changefeed resume --pd=http://10.1.xx.xx:23799 --changefeed-id=task-migrate-to-prod004
4、校验同步情况
- 查看上下游数据内容是否一致;
- 测试过滤是否生效:上游建表,测试表DML/DDL 是否同步到下游。
#上游建表
use db1;#本次迁移的多库之一
CREATE TABLE `zlz001` (
`id` bigint(20) NOT NULL auto_random COMMENT '主键',
`params` varchar(100) NOT NULL COMMENT '值',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`) /*T![clustered_index] NONCLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='测试表';
create database zlz;#非本次迁移的库
use zlz;
CREATE TABLE `zlz002` (
`id` bigint(20) unsigned NOT NULL auto_random COMMENT '主键ID',
`content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '短信内容',
`created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */
) ENGINE=InnoDB COMMENT='测试表';
insert into db1.zlz001(params) values('params'),('paramsparams'),('paramsparamsparamsparamsparams');
insert into zlz.zlz002(content) values('heeha');
#查看数据是否同步到下游
#有 timestamp 字段,需关注上下游集群的时区是否一致
select * from db1.zlz001;#本次同步的库,应查到数据
select * from zlz.zlz002;#非本次TiCDC同步的库,下游应查不到数据
#删表,查看数据是否同步到下游
drop table if exists db1.zlz001;
drop table if exists zlz.zlz002;
#清理测试库
drop database zlz;
这里就不写详细过程了。
第 4 步:平滑切换业务
通过 TiCDC 创建上下游的同步链路后,原集群的写入数据会以非常低的延迟同步到新集群,此时可以逐步将读流量迁移到新集群了。观察一段时间,如果新集群表现稳定,就可以将写流量接入新集群,步骤如下:
1、停止上游集群的写业务。
2、确认上游数据已全部同步到下游后,停止上游到下游集群的 changefeed。
停止旧集群到新集群的 changefeed
:
tiup ctl:v5.4.0 cdc changefeed pause --pd=http://10.1.xx.xx:2379 --changefeed-id=task-migrate-to-prod004
查看 changefeed
状态:
tiup ctl:v5.4.0 cdc changefeed query --pd=http://10.1.xx.xx:2379 --changefeed-id=task-migrate-to-prod004
[
{
"id": "task-migrate-to-prod004",
"summary": {
"state": "stopped",# 需要确认这里的状态为 stopped
"tso": 436640265844293633,
"checkpoint": "2022-10-13 17:40:28.178",# 确认这里的时间晚于停写的时间
"error": null
}
}
]
3、将写业务迁移到下游集群
- 3.1 写业务更新数据源IP
- 3.2 更新对应的数据源配置
4、观察一段时间后,等新集群表现稳定,便可以弃用原集群
5、删除 TiCDC 同步任务
【删除同步任务】:
tiup ctl:v5.4.0 cdc changefeed remove --pd=http://10.1.xx.xx:2379 --changefeed-id=task-zlz
【查看所有任务】:
tiup ctl:v5.4.0 cdc changefeed list --pd=http://10.1.xx.xx:2379
遇到问题
TiDB 集群时区问题
在测试上下游集群时,发现一个诡异的时区问题:
在执行 select now();
时,下游集群的时间比系统时间少了 8 小时。
在以往 v5.0 版本的 TiDB 集群,是可以在集群配置文件中增加 timezone
参数来设置时区的。比如:
server_configs:
tidb:
timezone:Asia/Ahanghai
但是,到了 v5.4.0 的版本,配置文件中不支持这个timezone
参数了。
所以,新集群安装好后,如果不通过系统变量设置一遍,就会出现这样时区默认是UTC
的问题。为什么会是 UTC
可以参考这篇 记一次 TiDB 时区设置异常问题排查 。(测试了下,在 v6.1.2 中没这个问题了。)
所以,在迁移 TiDB 集群时,需要关注上下游集群时区是否一致。
查看新集群时区设置:
mysql> SELECT @@global.time_zone, @@session.time_zone, @@global.system_time_zone;
+--------------------+---------------------+---------------------------+
| @@global.time_zone | @@session.time_zone | @@global.system_time_zone |
+--------------------+---------------------+---------------------------+
| SYSTEM | SYSTEM | UTC |
+--------------------+---------------------+---------------------------+
1 row in set (0.01 sec)
发现 system_time_zone
是 UTC
。而我们是东八区,需要'+8:00' 。如何修改时区呢?
时区异常解决办法
- 更新
mysql.tidb
中system_tz
为正确的时区,并重启tidb-server
。
mysql> update mysql.tidb set VARIABLE_VALUE='Asia/Shanghai' where VARIABLE_NAME='system_tz';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from mysql.tidb where variable_name='system_tz';
+---------------+----------------+------------------------------+
| VARIABLE_NAME | VARIABLE_VALUE | COMMENT |
+---------------+----------------+------------------------------+
| system_tz | Asia/Shanghai | TiDB Global System Timezone. |
+---------------+----------------+------------------------------+
1 row in set (0.00 sec)
- 根据官方文档修改时区,设置
time_zone
变量,问题也可以得到解决。如果有需要,可以把system_tz
也修改了,因为tidb-server
不会自行进行调整。
【修改时区】:
set global time_zone='Asia/Shanghai';
mysql> SELECT @@global.time_zone, @@session.time_zone, @@global.system_time_zone;
+--------------------+---------------------+---------------------------+
| @@global.time_zone | @@session.time_zone | @@global.system_time_zone |
+--------------------+---------------------+---------------------------+
| Asia/Shanghai | Asia/Shanghai | UTC |
+--------------------+---------------------+---------------------------+
1 row in set (0.00 sec)
- 也可以在
JDBC
链接中指定时区serverTimezone=Asia/Shanghai
。比如:
jdbc:mysql://10.1.1.1:4002/dbname?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useServerPrepStmts=true&cachePrepStmts=true&allowMultiQueries=true&useConfigs=maxPerformance&useSSL=false&serverTimezone=Asia/Shanghai
总结
本次迁移目的是做 TiDB 集群的合并(顺便升级TiDB版本), 使用到的工具有 Dumpling +Loader +TiCDC 。
TiCDC 是一款通过拉取 TiKV 变更日志实现的,用于上游是 TiDB 集群的增量数据同步工具。 所以,这个实践手册也适用于从 TiDB 回迁一些小库回 MySQL。
- TiCDC 的输入:TiDB 集群
- TiCDC 的输出:TiDB 集群、MySQL、Kafka、Apache Pulsar、Confluent
- 适用 TiDB 版本:v4.0.6 及以上
PS:想到 TiDB 集群的迁移,第一反应是头疼。但是有工具,瞬间看到了光亮。虽然第一遍部署因为不熟有点畏惧心理,但是任务部署好,不免多次感叹 TiCDC 真好用啊!