0
0
1
0
博客/.../

TiDB DM 数据迁移工具的配置与实践

 北南南北  发表于  2026-06-29

一、DM 架构解析

1.1 组件角色

DM 集群由三个核心组件构成:

DM 架构全景图:

┌──────────────────┐
│   DM-master      │  调度中枢
│  (Raft 高可用)    │
│  端口: 8261      │
└────────┬─────────┘
         │
    ┌────┴────┐
    v         v
┌───────┐ ┌───────┐
│DM-W1  │ │DM-W2  │  Worker,执行实际迁移
│端口:8262│ │端口:8262│
└───┬───┘ └───┬───┘
    │         │
    v         v
MySQL-A   MySQL-B         TiDB (下游)
(上游)    (上游)         10.0.1.14:4000
组件 角色 说明
DM-master 集群调度 基于 etcd 实现高可用,管理 Worker 分配和任务调度
DM-worker 任务执行 运行在 MySQL 所在机器,负责拉取 binlog 和执行迁移
dmctl 命令行工具 用户通过 dmctl 与 DM-master 交互,管理任务

1.2 数据流转过程

DM 数据迁移三阶段:

阶段 1: 全量迁移 (Loader)
┌────────┐        ┌────────┐        ┌────────┐
│ MySQL  │ ─dump─>│ 磁盘文件│ ─load─>│  TiDB  │
│        │ (SQL)   │ (.sql)  │        │        │
└────────┘        └────────┘        └────────┘

阶段 2: 增量同步 (Syncer)
┌────────┐        ┌────────┐        ┌────────┐
│ MySQL  │ ─binlog─>│ DM-W   │ ─relay─>│  TiDB  │
│        │ (binary) │        │ (SQL)   │        │
└────────┘        └────────┘        └────────┘

阶段 3: 持续同步 (可选)
┌────────┐   持续监控    ┌────────┐   持续写入   ┌────────┐
│ MySQL  │ ──────────> │ DM-W   │ ──────────> │  TiDB  │
│ (业务写入)│  binlog     │        │  重放       │        │
└────────┘             └────────┘             └────────┘

二、DM 集群部署

2.1 硬件需求

组件 CPU 内存 磁盘 说明
DM-master 4 核 8GB SSD 100GB etcd 对磁盘 I/O 敏感
DM-worker 8 核 16GB+ SSD 200GB+ 需要存储 relay log
监控 4 核 8GB 100GB Prometheus + Grafana

2.2 使用 TiUP 部署

# dm-topology.yaml
---

# 全局配置
global:
  user: "tidb"
  ssh_port: 22
  deploy_dir: "/dm-deploy"
  data_dir: "/dm-data"

# DM-master (推荐 3 节点高可用)
master_servers:
  - host: 10.0.1.50
    port: 8261
    peer_port: 8291
  - host: 10.0.1.51
    port: 8261
    peer_port: 8291
  - host: 10.0.1.52
    port: 8261
    peer_port: 8291

# DM-worker (每个 MySQL 源对应一个 worker)
worker_servers:
  - host: 10.0.2.10
    port: 8262
    deploy_dir: "/dm-deploy"
    data_dir: "/dm-data"
  - host: 10.0.2.20
    port: 8262
    deploy_dir: "/dm-deploy"
    data_dir: "/dm-data"
# 部署 DM 集群
tiup dm deploy dm-prod v8.5.0 dm-topology.yaml --user root

# 启动集群
tiup dm start dm-prod

# 查看状态
tiup dm display dm-prod

2.3 二进制部署(无 TiUP 环境)

# 下载 DM 二进制
wget https://download.pingcap.org/dm-v8.5.0-linux-amd64.tar.gz
tar -xzf dm-v8.5.0-linux-amd64.tar.gz

# 启动 DM-master
./bin/dm-master --config=dm-master.toml

# 启动 DM-worker
./bin/dm-worker --config=dm-worker.toml
# dm-master.toml
name = "dm-master-1"
data-dir = "/dm-data/master"
peer-urls = "0.0.0.0:8291"
advertise-peer-urls = "http://10.0.1.50:8291"
master-addr = ":8261"
advertise-addr = "10.0.1.50:8261"
initial-cluster = "dm-master-1=http://10.0.1.50:8291,dm-master-2=http://10.0.1.51:8291,dm-master-3=http://10.0.1.52:8291"
# dm-worker.toml
name = "dm-worker-1"
master-addr = "10.0.1.50:8261,10.0.1.51:8261,10.0.1.52:8261"
worker-addr = ":8262"
join = "http://10.0.1.50:8261"

三、配置数据源

3.1 数据源配置文件

# source1.yaml
source-id: "mysql-source-1"

# MySQL 连接信息
from:
  host: "192.168.1.100"
  port: 3306
  user: "root"
  password: "encrypted_password"  # 使用 dmctl encrypt 加密
  max-allowed-packet: 67108864  # 64MB

# 启用 relay log(可选,用于断点续传)
enable-relay: true
relay-binlog-name: "mysql-bin.000001"
relay-binlog-gtid: ""

# 安全连接(可选)
security:
  ssl-ca: "/path/to/ca.pem"
  ssl-cert: "/path/to/cert.pem"
  ssl-key: "/path/to/key.pem"
# 加密密码
tiup dmctl --master-addr 10.0.1.50:8261 operate-source create source1.yaml

# 查看数据源
tiup dmctl --master-addr 10.0.1.50:8261 operate-source show

# 查看数据源状态
tiup dmctl --master-addr 10.0.1.50:8261 query-status --source mysql-source-1

3.2 上游 MySQL 准备

DM 需要 MySQL 开启 binlog 并设置正确的格式:

-- 检查 MySQL binlog 配置
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW VARIABLES LIKE 'binlog_row_image';

-- 要求:
-- log_bin = ON
-- binlog_format = ROW
-- binlog_row_image = FULL

-- 如果未开启,修改 my.cnf:
-- [mysqld]
-- log-bin = mysql-bin
-- binlog-format = ROW
-- binlog-row-image = FULL
-- server-id = 1  # 每个 MySQL 实例必须唯一

DM 所需的 MySQL 权限:

-- 创建 DM 专用用户
CREATE USER 'dm_worker'@'%' IDENTIFIED BY 'your_password';

GRANT SELECT, RELOAD, LOCK TABLES, REPLICATION CLIENT, REPLICATION SLAVE, PROCESS ON *.* TO 'dm_worker'@'%';

FLUSH PRIVILEGES;

四、任务配置详解

4.1 完整任务配置

# task-full.yaml — 全量 + 增量迁移
---

# 任务名称(全局唯一)
name: "mysql-to-tidb-prod"

# 任务模式: full(全量), incremental(增量), all(全量+增量)
task-mode: "all"

# 是否启用增量同步的 relay log
is-sharding: false

# 处理不兼容的 DDL 策略
# - "fail" : 遇到不兼容 DDL 停止任务(默认)
# - "ignore": 忽略不兼容 DDL
ignore-checking-items: ["auto_increment_ID"]

# 目标 TiDB 配置
target-database:
  host: "10.0.1.14"
  port: 4000
  user: "root"
  password: ""
  max-allowed-packet: 67108864
  session:
    tidb_txn_mode: "pessimistic"
    tidb_disable_txn_auto_retry: "off"

# 上游 MySQL 实例列表
mysql-instances:
  - source-id: "mysql-source-1"
    # 库表过滤
    block-allow-list: "prod-filter"
    # 全量导出配置引用
    mydumper-config-name: "global-dump"
    # 全量导入配置引用
    loader-config-name: "global-load"
    # 增量同步配置引用
    syncer-config-name: "global-sync"
    # 表路由规则
    route-rules: ["route-rule-1"]
    # 列过滤规则
    filter-rules: ["filter-rule-1"]
    # 在线 DDL 处理方式
    online-ddl-scheme: "gh-ost"

  - source-id: "mysql-source-2"
    block-allow-list: "prod-filter"
    mydumper-config-name: "global-dump"
    loader-config-name: "global-load"
    syncer-config-name: "global-sync"

# 库表过滤规则
block-allow-list:
  prod-filter:
    do-dbs: ["ecommerce", "user_center"]
    do-tables:
      - db-name: "ecommerce"
        tbl-name: "~^(orders|order_items|products|categories)$"
      - db-name: "user_center"
        tbl-name: "~^(users|user_profiles|addresses)$"
    ignore-dbs: ["test", "performance_schema", "mysql"]

# Mydumper 全量导出配置
mydumpers:
  global-dump:
    rows: 200000        # 每个文件最大行数
    threads: 8          # 导出并发线程数
    chunk-filesize: "64" # 每个文件大小 (MB)
    extra-args: "--no-views --no-triggers"  # 额外参数

# Loader 全量导入配置
loaders:
  global-load:
    pool-size: 16       # 导入并发数
    dir: "./dumped_data" # 临时数据目录
    sorting-dir-physical: "/tmp/sorting"
    # 导入模式: "logical"(默认)或 "physical"
    import-mode: "logical"
    # on-duplicate: "replace" 或 "error" 或 "ignore"
    on-duplicate: "replace"

# Syncer 增量同步配置
syncers:
  global-sync:
    worker-count: 16    # 同步并发数
    batch: 100          # 每批处理的 binlog 事件数
    queue-size: 1024    # binlog 事件队列大小
    # 最大重试次数
    max-retry: 100
    # 自动跳过 DDL 错误的表(谨慎使用)
    # skip-ddls: ["ALTER TABLE"]

# 表路由规则(分库分表合并时使用)
routes:
  route-rule-1:
    # 源库匹配模式
    schema-pattern: "ecommerce_*"
    # 源表匹配模式
    table-pattern: "orders_*"
    # 目标库名
    target-schema: "ecommerce"
    # 目标表名
    target-table: "orders"

# 列过滤规则
filters:
  filter-rule-1:
    schema-pattern: "ecommerce"
    table-pattern: "orders"
    # 过滤掉特定类型的 binlog 事件
    events: ["truncate", "drop table"]
    sql-pattern: ["^DROP TABLE", "^TRUNCATE"]
    action: Ignore  # Ignore 或 Do

4.2 最小任务配置

对于简单的全库迁移:

# task-minimal.yaml
name: "simple-migration"
task-mode: "all"

target-database:
  host: "10.0.1.14"
  port: 4000
  user: "root"
  password: ""

mysql-instances:
  - source-id: "mysql-source-1"
    # 不做任何过滤,迁移所有库表

五、分库分表合并迁移

5.1 场景说明

MySQL 分库分表:

  db_01.users    ─┐
  db_02.users    ─┼──> TiDB: ecommerce.users(合并为一张表)
  db_03.users    ─┘

  db_01.orders_01  ─┐
  db_01.orders_02  ─┤
  db_02.orders_01  ─┼──> TiDB: ecommerce.orders
  db_02.orders_02  ─┘

5.2 乐观 shard-merge 配置

# task-sharding-optimistic.yaml
name: "sharding-merge-optimistic"
task-mode: "all"
is-sharding: true
shard-mode: "optimistic"  # 乐观模式:假设 DDL 顺序一致

target-database:
  host: "10.0.1.14"
  port: 4000
  user: "root"

mysql-instances:
  - source-id: "mysql-source-1"
    block-allow-list: "shard-filter"
    route-rules: ["shard-route"]
    syncer-config-name: "shard-sync"

block-allow-list:
  shard-filter:
    do-dbs: ["db_*"]
    do-tables:
      - db-name: "db_*"
        tbl-name: "~^(users|orders)_"

routes:
  shard-route:
    schema-pattern: "db_*"
    table-pattern: "users_*"
    target-schema: "ecommerce"
    target-table: "users"

syncers:
  shard-sync:
    worker-count: 16
    batch: 100
    # 乐观模式下 DM 假设所有分片的 DDL 按相同顺序执行
    # 如果 DDL 顺序不一致,可能导致数据不一致

5.3 悲观 shard-merge 配置

# task-sharding-pessimistic.yaml
name: "sharding-merge-pessimistic"
task-mode: "all"
is-sharding: true
shard-mode: "pessimistic"  # 悲观模式:等待所有分片 DDL 到达后再执行

5.4 处理分片 DDL 冲突

# 查看 DDL 锁
tiup dmctl --master-addr 10.0.1.50:8261 ddl --name sharding-merge-optimistic

# 解锁 DDL 锁(跳过某个分片的 DDL)
tiup dmctl --master-addr 10.0.1.50:8261 unlock-ddl-lock \
    --task sharding-merge-optimistic \
    <lock-id>

# 强制执行 DDL
tiup dmctl --master-addr 10.0.1.50:8261 unlock-ddl-lock \
    --task sharding-merge-optimistic \
    --exec 1 \
    <lock-id>

六、任务管理

6.1 启动任务

# 创建并启动任务
tiup dmctl --master-addr 10.0.1.50:8261 start-task task-full.yaml

# 指定 Worker 启动(多 Worker 场景)
tiup dmctl --master-addr 10.0.1.50:8261 start-task task-full.yaml \
    --source-workers mysql-source-1

6.2 查看任务状态

# 查看任务整体状态
tiup dmctl --master-addr 10.0.1.50:8261 query-status mysql-to-tidb-prod

# 查看子任务详情
tiup dmctl --master-addr 10.0.1.50:8261 query-status mysql-to-tidb-prod \
    --source mysql-source-1

# 输出示例:
# {
#   "result": true,
#   "msg": "",
#   "sources": [
#     {
#       "result": true,
#       "source": "mysql-source-1",
#       "worker": "10.0.2.10:8262",
#       "subTaskStatus": [
#         {
#           "name": "mysql-to-tidb-prod",
#           "stage": "Running",
#           "unit": "Sync",  ← 当前执行阶段
#           "sync": {
#             "totalEvents": 12345,
#             "totalTps": 567,
#             "recentTps": 123,
#             "masterBinlog": "(mysql-bin.000045, 12345678)",
#             "syncerBinlog": "(mysql-bin.000045, 12345678)",
#             "binlogType": "remote"
#           }
#         }
#       ]
#     }
#   ]
# }

6.3 暂停/恢复/停止任务

# 暂停任务
tiup dmctl --master-addr 10.0.1.50:8261 pause-task mysql-to-tidb-prod

# 暂停特定数据源的任务
tiup dmctl --master-addr 10.0.1.50:8261 pause-task mysql-to-tidb-prod \
    --source mysql-source-1

# 恢复任务
tiup dmctl --master-addr 10.0.1.50:8261 resume-task mysql-to-tidb-prod

# 停止任务(删除任务配置)
tiup dmctl --master-addr 10.0.1.50:8261 stop-task mysql-to-tidb-prod

6.4 修改任务配置

# 更新任务配置
tiup dmctl --master-addr 10.0.1.50:8261 update-task mysql-to-tidb-prod \
    task-updated.yaml

# 更新数据源配置
tiup dmctl --master-addr 10.0.1.50:8261 update-config mysql-source-1 \
    --task mysql-to-tidb-prod \
    source1-updated.yaml

七、增量同步与切换

7.1 增量同步状态判断

# 查看同步延迟
tiup dmctl --master-addr 10.0.1.50:8261 query-status mysql-to-tidb-prod

# 关键字段:
# masterBinlog:   MySQL 当前最新 binlog 位置
# syncerBinlog:   DM 已同步到的 binlog 位置
# 当两者一致时,说明增量已追平

7.2 切换流量

切换流程:

1. 应用停止向 MySQL 写入
   ↓
2. 等待 DM 追平最后一个 binlog 事件
   (masterBinlog == syncerBinlog)
   ↓
3. 数据一致性校验
   (使用 sync-diff-inspector)
   ↓
4. 切换应用连接至 TiDB
   ↓
5. 观察 TiDB 运行状态
   ↓
6. 停止 DM 任务
# 一致性校验
sync-diff-inspector \
    --config=check-config.yaml

# 停止 DM 任务
tiup dmctl --master-addr 10.0.1.50:8261 stop-task mysql-to-tidb-prod

八、DM Web UI

DM 提供 Web 界面管理迁移任务:

访问: http://10.0.1.50:8261
功能:
├── 任务列表 — 查看所有任务状态
├── 任务详情 — 查看同步进度、延迟、binlog 位置
├── 数据源管理 — 添加/删除数据源
├── 告警信息 — 查看任务告警
└── 操作日志 — 审计操作记录

九、故障排查

9.1 常见错误

错误 原因 解决
code=38020 binlog 格式不正确 检查 binlog_format=ROW
code=36027 上游连接失败 检查网络和 MySQL 状态
code=30064 DDL 执行失败 检查 DDL 语法兼容性
code=20032 数据源 ID 冲突 修改 source-id
code=30015 Loader 导入失败 检查 TiDB 连接和权限

9.2 处理失败的 DDL

# 查看失败的 DDL
tiup dmctl --master-addr 10.0.1.50:8261 operate-schema show \
    --task mysql-to-tidb-prod \
    --source mysql-source-1 \
    --database ecommerce \
    --table orders

# 跳过 DDL(手动修复后)
tiup dmctl --master-addr 10.0.1.50:8261 operate-schema set \
    --task mysql-to-tidb-prod \
    --source mysql-source-1 \
    --database ecommerce \
    --table orders \
    "CREATE TABLE orders (...)"  # 正确的 schema

9.3 日志查看

# DM-master 日志
tail -100 /dm-deploy/dm-master-8261/log/dm-master.log

# DM-worker 日志
tail -100 /dm-deploy/dm-worker-8262/log/dm-worker.log

# 查看特定任务的日志
grep "mysql-to-tidb-prod" /dm-deploy/dm-worker-8262/log/dm-worker.log

十、性能调优

10.1 全量迁移调优

mydumpers:
  global-dump:
    threads: 16         # 增加导出并发
    rows: 500000        # 增大文件行数,减少文件数量

loaders:
  global-load:
    pool-size: 32       # 增加导入并发
    import-mode: "physical"  # 大数据量使用物理导入

10.2 增量同步调优

syncers:
  global-sync:
    worker-count: 32    # 增加同步并发
    batch: 500          # 增大批次大小
    queue-size: 4096    # 增大队列

10.3 Relay Log 调优

# 在 source 配置中启用 relay log
enable-relay: true

# relay log 目录(需要足够空间)
relay-dir: "/dm-data/relay"

# 优点: 断点续传时不需重新拉取远端 binlog
# 缺点: 占用额外磁盘空间

0
0
1
0

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

评论
暂无评论