0
1
0
1
专栏/.../

TiCDC 实践:TiDB 集群合并

 Hacker_小峰  发表于  2022-10-14
原创迁移

背景

因降本的原因,需要将流量较小的 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_zoneUTC 。而我们是东八区,需要'+8:00' 。如何修改时区呢?

时区异常解决办法

  1. 更新 mysql.tidbsystem_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)
  1. 根据官方文档修改时区,设置 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)
  1. 也可以在 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 真好用啊!

0
1
0
1

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论