## 模块 2：将示例数据库从 MySQL 迁移并复制到 TiDB

### 步骤 1. 在 MySQL 中创建用于迁移的用户

+ 在[终端 1](ssh://monitor1-ssh#1) 上，连接到 MySQL server，创建一个专门用于迁移和复制的用户`dm_user`。

   ```bash
   X=q1w2e3R4_
   mysql -h localhost -P 3306 -uroot -p$X --connect-expired-password << EOF
   DROP USER IF EXISTS dm_user@'%';
   CREATE USER dm_user@'%' IDENTIFIED BY 'q1w2e3R4_';
   GRANT ALL PRIVILEGES ON *.* TO dm_user@'%';
   EXIT
   EOF
   ```

   ```output
   mysql: [Warning] Using a password on the command line interface can be insecure.
   ```

+ 退出到远程 TiUP 控制机。

   ```bash
   exit
   ```

   ```output
   logout
   Connection to 10.90.1.132 closed.
   ```

### 步骤 2. 验证 TiDB 集群已启动并正在运行

+ 检查 TiDB 集群状态。请注意，TiDB 集群 `tidb-demo` 中应该有 1 个 TiDB server，3 个 TiKV serverse 和 1 个 TiFlash server。

   ```bash
   ~/.tiup/bin/tiup cluster display tidb-demo
   ```

   ```output
   Cluster type:       tidb
   Cluster name:       tidb-demo
   Cluster version:    v8.1.0
   Deploy user:        ec2-user
   SSH type:           builtin
   Dashboard URL:      http://54.218.160.235:2379/dashboard
   Grafana URL:        http://10.90.4.225:3000
   ID                 Role          Host         Ports                            OS/Arch       Status  Data Dir                      Deploy Dir
   --                 ----          ----         -----                            -------       ------  --------                      ----------
   10.90.4.225:9093   alertmanager  10.90.4.225  9093/9094                        linux/x86_64  Up      /tidb-data/alertmanager-9093  /tidb-deploy/alertmanager-9093
   10.90.4.225:3000   grafana       10.90.4.225  3000                             linux/x86_64  Up      -                             /tidb-deploy/grafana-3000
   10.90.3.54:2379    pd            10.90.3.54   2379/2380                        linux/x86_64  Up|L    /tidb-data/pd-2379            /tidb-deploy/pd-2379
   10.90.4.225:9090   prometheus    10.90.4.225  9090/12020                       linux/x86_64  Up      /tidb-data/prometheus-9090    /tidb-deploy/prometheus-9090
   10.90.2.134:4000   tidb          10.90.2.134  4000/10080                       linux/x86_64  Up      -                             /tidb-deploy/tidb-4000
   10.90.4.150:9000   tiflash       10.90.4.150  9000/8123/3930/20170/20292/8234  linux/x86_64  Up      /tidb-data/tiflash-9000       /tidb-deploy/tiflash-9000
   10.90.1.183:20160  tikv          10.90.1.183  20160/20180                      linux/x86_64  Up      /tidb-data/tikv-20160         /tidb-deploy/tikv-20160
   10.90.1.251:20160  tikv          10.90.1.251  20160/20180                      linux/x86_64  Up      /tidb-data/tikv-20160         /tidb-deploy/tikv-20160
   10.90.1.41:20160   tikv          10.90.1.41   20160/20180                      linux/x86_64  Up      /tidb-data/tikv-20160         /tidb-deploy/tikv-20160
   Total nodes: 9
   ```

### 步骤 3. 在 TiDB 中创建用于迁移的用户

+ 在 TiDB 上创建一个专门用于迁移和复制的用户 `dm_user`。

   ```bash
   mysql -h ${HOST_DB1_PRIVATE_IP} -P 4000 -uroot << 'EOF'
   DROP USER IF EXISTS dm_user@'%';
   CREATE USER dm_user@'%' identified by 'q1w2e3R4_';
   GRANT ALL PRIVILEGES ON *.* TO dm_user@'%';
   EXIT
   EOF
   ```

### 步骤 4. 在 TiDB 中创建目标数据库

+ 在 TiDB 中创建目标数据库 `sp500insight` 及其空表。这些表包括 `companies`, `index_compositions`, `index_price_history`, `indexes`, `stock_price_history`, `user_selected_stocks` 和 `users`。

   ```bash
   mysql -h ${HOST_DB1_PRIVATE_IP} -P 4000 -uroot
   ```

   ```sql
   CREATE DATABASE sp500insight;
   USE sp500insight;
   CREATE TABLE `companies` (
     `stock_symbol` varchar(10) NOT NULL,
     `exchange_symbol` varchar(50) NOT NULL,
     `short_name` varchar(50) DEFAULT NULL,
     `long_name` varchar(100) DEFAULT NULL,
     `sector` varchar(50) DEFAULT NULL,
     `industry` varchar(50) DEFAULT NULL,
     `current_price` decimal(18,2) DEFAULT NULL,
     `market_cap` bigint(20) DEFAULT NULL,
     `ebitda` bigint(20) DEFAULT NULL,
     `revenue_growth` float DEFAULT NULL,
     `city` varchar(50) DEFAULT NULL,
     `state` varchar(50) DEFAULT NULL,
     `country` varchar(50) DEFAULT NULL,
     `country_code` varchar(3) DEFAULT NULL,
     `full_time_employees` int(11) DEFAULT NULL,
     `long_business_summary` text DEFAULT NULL,
     PRIMARY KEY (stock_symbol, exchange_symbol)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   CREATE TABLE `index_compositions` (
     `index_symbol` varchar(10) DEFAULT NULL,
     `stock_symbol` varchar(10) NOT NULL,
     `weight` double DEFAULT NULL,
     PRIMARY KEY (stock_symbol)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   CREATE TABLE `index_price_history` (
     `record_date` date NOT NULL,
     `index_symbol` varchar(10) NOT NULL,
     `price` decimal(18,2) DEFAULT NULL,
     PRIMARY KEY (record_date, index_symbol)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   CREATE TABLE `indexes` (
     `index_symbol` varchar(10) NOT NULL,
     `short_name` varchar(50) DEFAULT NULL,
     PRIMARY KEY (index_symbol)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   CREATE TABLE `stock_price_history` (
     `record_date` date NOT NULL,
     `stock_symbol` varchar(10) NOT NULL,
     `adj_close` decimal(32,16) DEFAULT NULL,
     `close` decimal(32,16) DEFAULT NULL,
     `high` decimal(32,16) DEFAULT NULL,
     `low` decimal(32,16) DEFAULT NULL,
     `open` decimal(32,16) DEFAULT NULL,
     `volume` bigint(20) DEFAULT NULL,
     PRIMARY KEY (record_date, stock_symbol)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   CREATE TABLE `user_selected_stocks` (
     `user_id` int(11) NOT NULL,
     `stock_symbol` varchar(10) NOT NULL,
     `created_date` datetime DEFAULT NULL,
     PRIMARY KEY (user_id, stock_symbol)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   CREATE TABLE `users` (
     `user_id` int(11) NOT NULL,
     `created_date` datetime DEFAULT NULL,
     PRIMARY KEY (user_id)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
   SET GLOBAL allow_auto_random_explicit_insert = true;
   ```

### 步骤 5. 为分析查询启用 TiFlash

+ 为  `sp500insight.stock_price_history` 表启用 TiFlash 分析列式存储。

   ```sql
   ALTER TABLE sp500insight.stock_price_history SET TIFLASH REPLICA 1;
   EXIT;
   ```

   ```output
   Query OK, 0 rows affected (0.10 sec)
   Bye
   ```

### 步骤 6. 安装 TiDB Data Migration 工具

+ 安装 TiDB Data Migration 组件。

   ```bash
   ~/.tiup/bin/tiup install dm dmctl:v${LAB:TIDB_VERSION} dm-master:v${LAB:TIDB_VERSION} dm-worker:v${LAB:TIDB_VERSION}
   ```

   ```bash
   ~/.tiup/bin/tiup list --verbose | grep dm
   ```

   ```output
   dm                 pingcap  v1.15.1,v1.16.0                     linux/amd64  Data Migration Platform manager
   dm-master          pingcap  v8.0.0,v${LAB:TIDB_VERSION}                       linux/amd64  dm-master component of Data Migration Platform.
   dm-worker          pingcap  v8.0.0,v${LAB:TIDB_VERSION}                       linux/amd64  dm-worker component of Data Migration Platform.
   dmctl              pingcap  v6.5.1,v6.5.9,v7.5.0,v${LAB:TIDB_VERSION}  linux/amd64  dmctl component of Data Migration Platform.
   ```

### 步骤 7. 查看 TiDB Data Migration 集群拓扑文件

+ TiDB Data Migration 集群拓扑配置文件已为你预配置好。请查看配置，无需更改。

   ```bash
   cat dm-topology.yaml
   ```

   ```output
   global:
     user: "ec2-user"
     ssh_port: 22
     deploy_dir: "/tidb-deploy"
     data_dir: "/tidb-data"
     arch: "amd64"
   master_servers:
     - host: 10.90.4.225
   worker_servers:
     - host: 10.90.4.225
   monitoring_servers:
     - host: 10.90.3.54
   grafana_servers:
     - host: 10.90.3.54
   alertmanager_servers:
     - host: 10.90.3.54
   ```

### 步骤 8. 部署并启动 TiDB Data Migration 集群

+ 部署 TiDB Data Migration 集群 - `dm-test`

   ```bash
   ~/.tiup/bin/tiup dm deploy dm-test v${LAB:TIDB_VERSION} ./dm-topology.yaml \
    --user ec2-user \
    -i /home/ec2-user/.ssh/pe-class-key-${LAB:REGION_NAME}.pem \
    --yes
   ```

   ```output
   Starting component dm: /home/ec2-user/.tiup/components/dm/v1.16.0/tiup-dm deploy dm-test v${LAB:TIDB_VERSION} ./dm-topology.yaml --user ec2-user -i /home/ec2-user/.ssh/pe-class-key-${LAB:REGION_NAME}.pem --yes
   + Detect CPU Arch Name
   .
   .
   .
   Cluster `dm-test` deployed successfully, you can start it with command: `tiup dm start dm-test`
   ```

+ 启动 TiDB Data Migration 集群 - `dm-test`.

   ```bash
   ~/.tiup/bin/tiup dm start dm-test
   ```

   ```output
   Starting component dm: /home/ec2-user/.tiup/components/dm/v1.16.0/tiup-dm start dm-test
   Starting cluster dm-test...
   + [ Serial ] - SSHKeySet: privateKey=/home/ec2-user/.tiup/storage/dm/clusters/dm-test/ssh/id_rsa, publicKey=/home/ec2-user/.tiup/storage/dm/clusters/dm-test/ssh/id_rsa.pub
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.1.7
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.3.71
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.1.7
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.4.191
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.1.7
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.3.49
   + [Parallel] - UserSSH: user=ec2-user, host=10.90.3.135
   + [ Serial ] - StartCluster
   Starting component dm-master
   	Starting instance 10.90.4.191:8261
   	Start instance 10.90.4.191:8261 success
   Starting component dm-worker
   	Starting instance 10.90.3.135:8262
   	Starting instance 10.90.3.49:8262
   	Starting instance 10.90.3.71:8262
   	Start instance 10.90.3.135:8262 success
   	Start instance 10.90.3.71:8262 success
   	Start instance 10.90.3.49:8262 success
   Starting component prometheus
   	Starting instance 10.90.1.7:9090
   	Start instance 10.90.1.7:9090 success
   Starting component grafana
   	Starting instance 10.90.1.7:3000
   	Start instance 10.90.1.7:3000 success
   Starting component alertmanager
   	Starting instance 10.90.1.7:9093
   	Start instance 10.90.1.7:9093 success
   Started cluster `dm-test` successfully
   ```

+ 确认 TiDB Data Migration 集群已启动并正在运行。

   ```bash
   tiup dm display dm-test
   ```

   ```output
   Starting component dm: /home/ec2-user/.tiup/components/dm/v1.16.0/tiup-dm display dm-test
   Cluster type:       dm
   Cluster name:       dm-test
   Cluster version:    v${LAB:TIDB_VERSION}
   Deploy user:        ec2-user
   SSH type:           builtin
   Grafana URL:        http://10.90.3.188:3000
   ID                Role          Host         Ports      OS/Arch       Status     Data Dir                      Deploy Dir
   --                ----          ----         -----      -------       ------     --------                      ----------
   10.90.3.188:9093  alertmanager  10.90.3.188  9093/9094  linux/x86_64  Up         /tidb-data/alertmanager-9093  /tidb-deploy/alertmanager-9093
   10.90.4.196:8261  dm-master     10.90.4.196  8261/8291  linux/x86_64  Healthy|L  /tidb-data/dm-master-8261     /tidb-deploy/dm-master-8261
   10.90.4.196:8262  dm-worker     10.90.4.196  8262       linux/x86_64  Free       /tidb-data/dm-worker-8262     /tidb-deploy/dm-worker-8262
   10.90.3.188:3000  grafana       10.90.3.188  3000       linux/x86_64  Up         -                             /tidb-deploy/grafana-3000
   10.90.3.188:9090  prometheus    10.90.3.188  9090       linux/x86_64  Up         /tidb-data/prometheus-9090    /tidb-deploy/prometheus-9090
   Total nodes: 5
   ```

### 步骤 9. 配置迁移源

+ 设置迁移任务源配置。

   ```bash
   cat << EOF > mysql-source-conf1.yaml
   source-id: "mysql-replica-01"
   from:
     host: "${HOST_MYSQL1_PRIVATE_IP}"
     port: 3306
     user: "dm_user"
     password: "q1w2e3R4_"
   EOF
   cat mysql-source-conf1.yaml
   ```

   ```output
   source-id: "mysql-replica-01"
   from:
     host: "10.90.1.135"
     port: 3306
     user: "dm_user"
     password: "q1w2e3R4_"
   ```

+ 将 MySQL 实例设置为迁移源，并验证 TiDB 数据迁移集群能够识别该源。

   ```bash
   ~/.tiup/bin/tiup dmctl:v${LAB:TIDB_VERSION} \
    --master-addr=${HOST_MONITOR1_PRIVATE_IP}:8261 operate-source create mysql-source-conf1.yaml
   ```

   ```output
   Starting component dmctl: /home/ec2-user/.tiup/components/dmctl/v${LAB:TIDB_VERSION}/dmctl/dmctl --master-addr=10.90.4.66:8261 operate-source create mysql-source-conf1.yaml
   {
       "result": true,
       "msg": "",
       "sources": [
           {
               "result": true,
               "msg": "",
               "source": "mysql-replica-01",
               "worker": "dm-10.90.3.187-8262"
           }
       ]
   }
   ```

   ```bash
   ~/.tiup/bin/tiup dmctl:v${LAB:TIDB_VERSION} \
    --master-addr=${HOST_MONITOR1_PRIVATE_IP}:8261 get-config source mysql-replica-01
   ```

   ```output
   Starting component dmctl: /home/ec2-user/.tiup/components/dmctl/v${LAB:TIDB_VERSION}/dmctl/dmctl --master-addr=10.90.4.66:8261 get-config source mysql-replica-01
   {
       "result": true,
       "msg": "",
       "cfg": "enable: true\nenable-gtid: false\nauto-fix-gtid: false\nrelay-dir: relay-dir\nmeta-dir: \"\"\nflavor: mysql\ncharset: \"\"\nenable-relay: false\nrelay-binlog-name: \"\"\nrelay-binlog-gtid: \"\"\nsource-id: mysql-replica-01\nfrom:\n  host: 10.90.1.135\n  port: 3306\n  user: dm_user\n  password: '******'\n  max-allowed-packet: null\n  session: {}\n  security: null\npurge:\n  interval: 3600\n  expires: 0\n  remain-space: 15\nchecker:\n  check-enable: true\n  backoff-rollback: 5m0s\n  backoff-max: 5m0s\n  check-interval: 5s\n  backoff-min: 1s\n  backoff-jitter: true\n  backoff-factor: 2\nserver-id: 429530419\ntracer: {}\ncase-sensitive: false\nfilters: []\n"
   }
   ```

   ```bash
   ~/.tiup/bin/tiup dmctl:v${LAB:TIDB_VERSION} \
    --master-addr=${HOST_MONITOR1_PRIVATE_IP}:8261 operate-source show
   ```

   ```output
   Starting component dmctl: /home/ec2-user/.tiup/components/dmctl/v${LAB:TIDB_VERSION}/dmctl/dmctl --master-addr=10.90.4.66:8261 operate-source show
   {
       "result": true,
       "msg": "",
       "sources": [
           {
               "result": true,
               "msg": "",
               "source": "mysql-replica-01",
               "worker": "dm-10.90.3.187-8262"
           }
       ]
   }
   ```

### 步骤 10. 创建并启动迁移任务

+ 创建迁移任务配置并启动迁移任务。该任务将持续把 `sp500insight` 数据库的更改从 MySQL server 迁移并复制到 TiDB 集群。

+ 生成迁移任务配置。

   ```bash
   cat << EOF > dm-task.yaml
   name: "dm-task"
   task-mode: all
   ignore-checking-items: ["auto_increment_ID"]

   target-database:
     host: "${HOST_DB1_PRIVATE_IP}"
     port: 4000
     user: "dm_user"
     password: "q1w2e3R4_"

   mysql-instances:
     - source-id: "mysql-replica-01"
       route-rules: ["instance-1-user-schema-rule"]
       block-allow-list: "rule_1"
       mydumper-config-name: "global"
       loader-config-name: "global"

   routes:
     instance-1-user-schema-rule:
       schema-pattern: "sp500insight"
       target-schema: "sp500insight"

   block-allow-list:
     rule_1:
       do-dbs: ["sp500insight"]

   mydumpers:
     global:
       threads: 32
       chunk-filesize: 64

   loaders:
     global:
       pool-size: 8
       import-mode: "physical"
       pd-addr: "${HOST_PD1_PRIVATE_IP}:2379"
   EOF
   cat dm-task.yaml
   ```

    ```output
    name: "dm-task"
    task-mode: all
    ignore-checking-items: ["auto_increment_ID"]
    .
    .
    .
    loaders:
      global:
        pool-size: 32
        import-mode: "physical"
    ```

+ 预检查迁移任务。msg 应显示 `pre-check is passed`.

  ```bash
  ~/.tiup/bin/tiup dmctl:v${LAB:TIDB_VERSION} \
    --master-addr=${HOST_MONITOR1_PRIVATE_IP}:8261 check-task ./dm-task.yaml
  ```

  ```output
  Starting component dmctl: /home/ec2-user/.tiup/components/dmctl/v${LAB:TIDB_VERSION}/dmctl/dmctl --master-addr=10.90.4.235:8261 check-task ./dm-task.yaml
  {
  "result": true,
  "msg": "pre-check is passed. "
  }
    ```

+ 启动迁移和复制任务，并检查迁移进度。

   ```bash
   ~/.tiup/bin/tiup dmctl:v${LAB:TIDB_VERSION} \
    --master-addr=${HOST_MONITOR1_PRIVATE_IP}:8261 start-task ./dm-task.yaml
   ```

   ```output
   Starting component dmctl: /home/ec2-user/.tiup/components/dmctl/v${LAB:TIDB_VERSION}/dmctl/dmctl --master-addr=10.90.4.66:8261 start-task ./dm-task.yaml
   {
       "result": true,
       "msg": "",
       "sources": [
           {
               "result": true,
               "msg": "",
               "source": "mysql-replica-01",
               "worker": "dm-10.90.3.187-8262"
           }
       ],
       "checkResult": "pre-check is passed. "
   }
   ```

### 步骤 11. 检查迁移进度

+ 多次使用 `query-status` 操作检查迁移状态。注意 `subTaskStatus` 中的 `stage`, `unit` 和 `progress` 属性。该任务包含 3 个子任务单元：`Dump`, `Load` 和 `Sync`。

+ 使用 `watch` 命令监控整个任务的进度。阅读以下更多信息，并在屏幕上观察迁移进度。

   ```bash
   watch -n 1 -d ~/.tiup/bin/tiup dmctl:v${LAB:TIDB_VERSION} --master-addr=${HOST_MONITOR1_PRIVATE_IP}:8261 query-status ./dm-task.yaml
   ```

+ 单元 `Dump`, 阶段 `Running`:

    ```output
    {
    ...
          "subTaskStatus": [
              {
                  "name": "dm-task",
                  "stage": "Running",
                  "unit": "Dump",
                  "result": null,
                  "unresolvedDDLLockID": "",
                  "dump": {
                      "totalTables": "6",
                      "completedTables": 3,
                      "finishedBytes": 7949200595,
                      "finishedRows": 39359277,
                      "estimateTotalRows": 59224808,
                      "bps": "57472325",
                      "progress": "64.63 %"
                  },
                  "validation": null
              }
          ]
      }
    ]
    }
    ```

+ 单元 `Load`, 阶段 `Running`:

    ```output
    {
    ...
             "subTaskStatus": [
                 {
                     "name": "dm-task",
                     "stage": "Running",
                     "unit": "Load",
                     "result": null,
                     "unresolvedDDLLockID": "",
                     "load": {
                         "finishedBytes": "5307344924",
                         "totalBytes": "8161057816",
                         "progress": "65.03 %",
                         "metaBinlog": "(binlog.000008, 157240317)",
                         "metaBinlogGTID": "",
                         "bps": "62882221"
                     },
                     "validation": null
                 }
             ]
         }
     ]
    }
    ```

+ 单元 `Sync`, 阶段 `Running`. 请注意目标 TiDB 和源 MySQL 已同步。

    ```output
    {
    ...
                "subTaskStatus": [
                    {
                        "name": "dm-task",
                        "stage": "Running",
                        "unit": "Sync",
                        "result": null,
                        "unresolvedDDLLockID": "",
                        "sync": {
                            "totalEvents": "19767046",
                            "totalTps": "21118",
                            "recentTps": "0",
                            "masterBinlog": "(binlog.000011, 706201359)",
                            "masterBinlogGtid": "",
                            "syncerBinlog": "(binlog.000011, 706201359)",
                            "syncerBinlogGtid": "00000000-0000-0000-0000-000000000000:0",
                            "blockingDDLs": [
                            ],
                            "unresolvedGroups": [
                            ],
                            "synced": true,
                            "binlogType": "remote",
                            "secondsBehindMaster": "0",
                            "blockDDLOwner": "",
                            "conflictMsg": "",
                            "totalRows": "19767046",
                            "totalRps": "21118",
                            "recentRps": "0"
                        },
                        "validation": null
                    }
                ]
            }
        ]
    }
    ```

> [!TIP]
> 动手实验里我们使用的是小型实例，能力远不如生产等级，请耐心等待几分钟直到同步完成。

+等待并确认迁移和复制的 `subTaskStatus` 已达到 `"stage": "Running"` 和 `"unit": "Sync"` 状态。保持 `watch` 命令运行，然后继续下一个练习。
