From f82ff89d09b96610be81822fcb9c2473988e73a8 Mon Sep 17 00:00:00 2001 From: Chunzhu Li Date: Mon, 21 Mar 2022 20:08:43 +0800 Subject: [PATCH 1/6] add unlock ddl lock doc --- dm/manually-handling-sharding-ddl-locks.md | 312 ++++++++++++++++++++- 1 file changed, 304 insertions(+), 8 deletions(-) diff --git a/dm/manually-handling-sharding-ddl-locks.md b/dm/manually-handling-sharding-ddl-locks.md index eb8e3bd26b9e..207cf41d7d33 100644 --- a/dm/manually-handling-sharding-ddl-locks.md +++ b/dm/manually-handling-sharding-ddl-locks.md @@ -5,11 +5,13 @@ aliases: ['/docs-cn/tidb-data-migration/dev/manually-handling-sharding-ddl-locks # 手动处理 Sharding DDL Lock -DM (Data Migration) 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。绝大多数情况下,该锁定机制可自动完成;但在部分异常情况发生时,需要使用 `shard-ddl-lock` 手动处理异常的 DDL lock。 +DM (Data Migration) 目前存在[悲观模式](/dm/feature-shard-merge-pessimistic.md)与[乐观模式](/dm/feature-shard-merge-optimistic.md)两种分库分表合并迁移模式,这两种模式中均存在 `shard-ddl-lock` 的概念,但是其实际作用略有不同。 + +1. 在悲观模式中,DM 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。绝大多数情况下,该锁定机制可自动完成;但在部分异常情况发生时,需要使用 `shard-ddl-lock` 手动处理异常的 DDL lock。 +2. 在乐观模式中,DM 使用表结构与 DDL 信息来确保分库分表的 DDL 操作可以正确执行。sharding DDL Lock 在乐观模式中用于表示是否所有分表可以生成兼容表结构。绝大多数情况不需人为干预,仅当分库分表表结构存在不可解冲突时,才可以使用 `shard-ddl-lock` 手动处理异常表结构。 > **注意:** > -> - 本文档只适用于悲观协调模式下 sharding DDL lock 的处理。 > - 本文档的命令在交互模式中进行,因此在以下命令示例中未添加转义字符。在命令行模式中,你需要添加转义字符,防止报错。 > - 不要轻易使用 `shard-ddl-lock unlock` 命令,除非完全明确当前场景下使用这些命令可能会造成的影响,并能接受这些影响。 > - 在手动处理异常的 DDL lock 前,请确保已经了解 DM 的[分库分表合并迁移原理](/dm/feature-shard-merge-pessimistic.md#实现原理)。 @@ -59,7 +61,7 @@ Use "dmctl shard-ddl-lock [command] --help" for more information about a command 使用 `shard-ddl-lock [task] [flags]` 命令,查询当前 DM-master 上存在的 DDL lock 信息。 -例如: +悲观模式: ```bash shard-ddl-lock test @@ -77,7 +79,7 @@ shard-ddl-lock test "ID": "test-`shard_db`.`shard_table`", # lock 的 ID 标识,当前由任务名与 DDL 对应的 schema/table 信息组成 "task": "test", # lock 所属的任务名 "mode": "pessimistic" # shard DDL 协调模式,可为悲观模式 "pessimistic" 或乐观模式 "optimistic" - "owner": "mysql-replica-01", # lock 的 owner(在悲观模式时为第一个遇到该 DDL 的 source ID),在乐观模式时总为空 + "owner": "mysql-replica-01", # lock 的 owner,在悲观模式时为第一个遇到该 DDL 的 source ID "DDLs": [ # 在悲观模式时为 lock 对应的 DDL 列表,在乐观模式时总为空 "USE `shard_db`; ALTER TABLE `shard_db`.`shard_table` DROP COLUMN `c2`;" ], @@ -94,13 +96,51 @@ shard-ddl-lock test +乐观模式: + +```bash +shard-ddl-lock test +``` + +
+期望输出 + +``` +{ + "result": true, # 查询 lock 操作本身是否成功 + "msg": "", # 查询 lock 操作失败时的原因或其它描述信息(如不存在任务 lock) + "locks": [ # 当前存在的 lock 信息列表 + { + "ID": "test-`shardddl`.`tb`", # lock 的 ID 标识,当前由任务名与 DDL 对应的 schema/table 信息组成 + "task": "test", # lock 所属的任务名 + "mode": "optimistic", # shard DDL 协调模式,可为悲观模式 "pessimistic" 或乐观模式 "optimistic" + "owner": "mysql-replica-02-`shardddl1`.`tb1`", # lock 的 owner,在乐观模式时为 DDL 存在冲突的上游分表的 source-`database`.`table` 格式信息 + "DDLs": [ # 在乐观模式时为 lock 冲突时的 DDL 列表,未出现冲突时为空 + "ALTER TABLE `shardddl`.`tb` MODIFY COLUMN `b` INT DEFAULT -1" + ], + "synced": [ # 已经收到对应 MySQL 实例内所有分表 DDL 的上游 source-`database`.`table` 分表列表 + "mysql-replica-01-`shardddl1`.`tb1`" + ], + "unsynced": [ # 尚未收到对应 MySQL 实例内所有分表 DDL 的上游 source-`database`.`table` 分表列表 + "mysql-replica-02-`shardddl1`.`tb1`", + "mysql-replica-02-`shardddl1`.`tb2`" + ] + } + ] +} +``` + +
+ ### `shard-ddl-lock unlock` -用于主动请求 DM-master 解除指定的 DDL lock,包括的操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 +用于主动请求 DM-master 解除指定的 DDL lock。 +1. 悲观模式 `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 +2. 乐观模式 `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 > **注意:** > -> `shard-ddl-lock unlock` 当前仅对悲观协调模式 (`pessimistic`) 下产生的 lock 有效。 +> `shard-ddl-lock unlock` 在 DM v6.0 以前版本仅对悲观协调模式 (`pessimistic`) 下产生的 lock 有效。 {{< copyable "shell-regular" >}} @@ -126,7 +166,7 @@ Global Flags: -s, --source strings MySQL Source ID. ``` -`shard-ddl-lock unlock` 命令支持以下参数: +悲观模式相关参数: + `-o, --owner`: - flag 参数,string,可选 @@ -141,6 +181,30 @@ Global Flags: - 非 flag 参数,string,必选 - 指定需要执行 unlock 操作的 DDL lock ID(即 `shard-ddl-lock` 返回结果中的 `ID`) +乐观模式相关参数 + ++ `-a, --action`: + - flag 参数,string,可选 + - 不指定时,请求指定的上游表跳过该冲突 DDL 操作;指定为 exec 时,请求该上游表执行引起冲突的 DDL 操作 + - 除非执行前已对下游合表表结构进行了适配修改,否则不应该指定为 exec 执行冲突 DDL。 + ++ `-s, --source`: + - flag 参数,string,乐观模式必填且目前只支持写一个 + - 执行需要执行 unlock 操作的上游的 source ID,可通过 `shard-ddl-lock` 命令获取 + ++ `-d, --database`: + - flag 参数,string,乐观模式必填且目前只支持写一个 + - 执行需要执行 unlock 操作的上游的数据库名称,可通过 `shard-ddl-lock` 命令获取 + ++ `-t, --table`: + - flag 参数,string,乐观模式必填且目前只支持写一个 + - 执行需要执行 unlock 操作的上游的表名称,可通过 `shard-ddl-lock` 命令获取 + ++ `lock-id`: + - 非 flag 参数,string,必选 + - 指定需要执行 unlock 操作的 DDL lock ID(即 `shard-ddl-lock` 返回结果中的 `ID`) + + 以下是一个使用 `shard-ddl-lock unlock` 命令的示例: {{< copyable "shell-regular" >}} @@ -158,7 +222,7 @@ shard-ddl-lock unlock test-`shard_db`.`shard_table` ## 支持场景 -目前,使用 `shard-ddl-lock unlock` 命令仅支持处理以下两种 sharding DDL lock 异常情况。 +目前,使用 `shard-ddl-lock unlock` 命令仅支持处理以下三种 sharding DDL lock 异常情况。 ### 场景一:部分 MySQL source 被移除 @@ -401,3 +465,235 @@ MySQL 及 DM 操作与处理流程如下: #### 手动处理后的影响 手动 unlock sharding DDL lock 后,后续的 sharding DDL 将可以自动正常迁移。 + +### 场景三:乐观模式协调过程中出现表结构冲突 + +#### Lock 异常原因 + +在 DM-master 尝试自动协调乐观 DDL,需要等待所有 MySQL source 的表结构达到一致状态,锁信息才会被清除(详见[乐观分表合并协调原理](/dm/feature-shard-merge-optimistic.md#原理))。如果 sharding DDL 在迁移过程中出现分表的 DDL 生成了不一致表结构,例如部分分表添加 default 0 的列而部分添加 default 1 的列,将造成 master 无法生成兼容表结构从而使得 lock 无法自动 unlock。 + +#### 手动处理示例 + +假设上游有 MySQL-1(`mysql-replica-01`)和 MySQL-2(`mysql-replica-02`)两个实例,其中 MySQL-1 中有 `shardddl1`.`tb1` 一个表,MySQL-2 中有 `shardddl1`.`tb1` 和 `shardddl1`.`tb2` 两个表。现在需要将这 3 个表合并后迁移到下游 TiDB 的 `shardddl`.`tb` 表中。 + +初始表结构如下: + +{{< copyable "sql" >}} + +```sql +SHOW CREATE TABLE shardddl1.tb1; +``` + +``` ++---------------+-------------------------------------------+ +| Table | Create Table | ++---------------+-------------------------------------------+ +| tb1 | CREATE TABLE `tb1` ( + `a` int(11) NOT NULL, + `b` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin | ++---------------+-------------------------------------------+ +``` + +上游 MySQL-1 实例下的分表将执行以下 DDL 语句变更表结构: + +{{< copyable "sql" >}} + +```sql +ALTER TABLE shardddl*.tb* MODIFY b INT DEFAULT 0; +``` + +上游 MySQL-2 实例下的分表将执行以下 DDL 语句变更表结构: + +{{< copyable "sql" >}} + +```sql +ALTER TABLE shardddl*.tb* MODIFY b INT DEFAULT -1; +``` + +MySQL 及 DM 操作与处理流程如下: + +1. `mysql-replica-01` 对应的分表执行了对应的 DDL 操作进行表结构变更。 + + {{< copyable "sql" >}} + + ```sql + ALTER TABLE shardddl1.tb1 MODIFY b INT DEFAULT 0; + ``` + +2. DM-worker 接受到 `mysql-replica-01` 分表的 DDL 之后,将对应的 DDL 信息发送给 DM-master,DM-master 创建相应的 DDL lock。 +3. 使用 `shard-ddl-lock` 查看当前的 DDL lock 信息。 + + {{< copyable "shell-regular" >}} + + ```bash + shard-ddl-lock test + ``` + + ``` + { + "result": true, + "msg": "", + "locks": [ + { + "ID": "test-`shardddl`.`tb`", + "task": "test", + "mode": "optimistic", + "owner": "", + "DDLs": [ + ], + "synced": [ + "mysql-replica-01-`shardddl1`.`tb1`" + ], + "unsynced": [ + "mysql-replica-02-`shardddl1`.`tb1`", + "mysql-replica-02-`shardddl1`.`tb2`" + ] + } + ] + } + ``` + + +4. 由于业务需要,`mysql-replica-02` 对应的分表添加的列默认值为 -1,但下游最终结构希望默认值为 0。 +5. DM-worker 接受到 `mysql-replica-02` 分表的 DDL 之后,将对应的 DDL 信息发送给 DM-master,DM-master 无法生成兼容表结构,MySQL-2 上的同步暂停。此时使用 `shard-ddl-lock` 和 `query-status test` 命令可以查到具体问题: + + {{< copyable "shell-regular" >}} + + ```bash + shard-ddl-lock test + ``` + + ``` + { + "result": true, + "msg": "", + "locks": [ + { + "ID": "test-`shardddl`.`tb`", + "task": "test", + "mode": "optimistic", + "owner": "mysql-replica-02-`shardddl1`.`tb1`", + "DDLs": [ + "ALTER TABLE `shardddl`.`tb` MODIFY COLUMN `b` INT DEFAULT -1" + ], + "synced": [ + "mysql-replica-01-`shardddl1`.`tb1`" + ], + "unsynced": [ + "mysql-replica-02-`shardddl1`.`tb1`", + "mysql-replica-02-`shardddl1`.`tb2`" + ] + } + ] + } + ``` + + ```bash + query-status test + ``` + + ``` + ... + { + "result": true, + "msg": "", + "sourceStatus": { + "source": "mysql-replica-02", + "worker": "worker2", + ... + }, + "subTaskStatus": [ + { + "name": "test", + "stage": "Running", + "unit": "Sync", + "result": null, + "unresolvedDDLLockID": "", + "sync": { + ... + "synced": false, + "binlogType": "local", + "secondsBehindMaster": "0", + "blockDDLOwner": "mysql-replica-02-`shardddl1`.`tb1`", + "conflictMsg": "[code=11111:class=functional:scope=internal:level=medium], Message: fail to try sync the optimistic shard ddl lock test-`shardddl`.`tb`: there will be conflicts if DDLs ALTER TABLE `shardddl`.`tb` MODIFY COLUMN `b` INT DEFAULT -1 are applied to the downstream. old table info: CREATE TABLE `tbl`(`a` INT(11) NOT NULL, `b` INT(11) NOT NULL, PRIMARY KEY (`a`)) CHARSET UTF8MB4 COLLATE UTF8MB4_BIN, new table info: CREATE TABLE `tbl`(`a` INT(11) NOT NULL, `b` INT(11) DEFAULT -1, PRIMARY KEY (`a`)) CHARSET UTF8MB4 COLLATE UTF8MB4_BIN, Workaround: Please use `show-ddl-locks` command for more details." + } + } + ] + } + ... + ``` + +6. DM-master 上 ID 为 ```test-`shardddl`.`tb` ``` 的 lock 无法为 `mysql-replica-02` 上的 `shardddl1`.`tb1` 的 DDL 生成兼容表结构, + +`shard-ddl-lock` 返回的 `unsynced` 中一直包含 `mysql-replica-02` 的信息。 + +7. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 该 DDL lock。 + + - 在乐观模式执行 `shard-ddl-lock unlock` 时需要指定 `-s,-d,-t` 为上文中的 `blockDDLOwner` 中的信息,每个参数均需要且仅指定一个值。 + - 当存在任意 MySQL source 报错时,`result` 将为 `false`,此时请仔细检查各 MySQL source 的错误是否是预期可接受的。 + + {{< copyable "shell-regular" >}} + + ```bash + shard-ddl-lock unlock 'test-`shardddl`.`tb`' -s mysql-replica-02 -d shardddl1 -t tb1 --action skip + ``` + + ``` + { + "result": true, + "msg": "" + ``` + +8. 重复该操作跳过第二个分表的 DDL。 +9. 使用 `shard-ddl-lock` 确认 DDL lock 是否被成功 unlock。 + + ```bash + shard-ddl-lock test + ``` + + ``` + { + "result": true, + "msg": "no DDL lock exists", + "locks": [ + ] + } + ``` + +10. 查看下游 TiDB 中的表结构是否变更成功。 + + {{< copyable "sql" >}} + + ```sql + SHOW CREATE TABLE shardddl.tb; + ``` + + ``` + +-------------+--------------------------------------------------+ + | Table | Create Table | + +-------------+--------------------------------------------------+ + | tb | CREATE TABLE `tb` ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT '0', + PRIMARY KEY (`a`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin + +-------------+--------------------------------------------------+ + ``` + +11. 使用 `query-status` 确认迁移任务是否正常。 + +#### 手动处理后的影响 + +使用 `shard-ddl-lock unlock` 手动执行 unlock 操作后,由于出错分表的表结构中仍然包含了不兼容的表信息,如果不进行处理,则当下次 sharding DDL 到达时,仍会出现 lock 无法自动完成迁移的情况。 + +因此,在手动解锁 DDL lock 后,需要再执行以下操作: + +1. 使用 `pause-task` 暂停运行中的任务。 +2. 使用 `binlog-schema update` 更新 skip 的表的表结构为兼容的表结构。 +3. 使用 `resume-task` 恢复任务运行。 + +> **注意:** +> +> 在某些场景下 `shard-ddl-lock unlock` 时,如果下游不进行手动处理,可能会引起上下游数据不一致。 From 9aa3317cc0131fc974e01495da00acb9e8da5018 Mon Sep 17 00:00:00 2001 From: Chunzhu Li Date: Tue, 22 Mar 2022 10:19:34 +0800 Subject: [PATCH 2/6] fix lint --- dm/manually-handling-sharding-ddl-locks.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dm/manually-handling-sharding-ddl-locks.md b/dm/manually-handling-sharding-ddl-locks.md index 207cf41d7d33..c7bb0715e86b 100644 --- a/dm/manually-handling-sharding-ddl-locks.md +++ b/dm/manually-handling-sharding-ddl-locks.md @@ -135,6 +135,7 @@ shard-ddl-lock test ### `shard-ddl-lock unlock` 用于主动请求 DM-master 解除指定的 DDL lock。 + 1. 悲观模式 `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 2. 乐观模式 `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 @@ -204,7 +205,6 @@ Global Flags: - 非 flag 参数,string,必选 - 指定需要执行 unlock 操作的 DDL lock ID(即 `shard-ddl-lock` 返回结果中的 `ID`) - 以下是一个使用 `shard-ddl-lock unlock` 命令的示例: {{< copyable "shell-regular" >}} @@ -555,7 +555,6 @@ MySQL 及 DM 操作与处理流程如下: } ``` - 4. 由于业务需要,`mysql-replica-02` 对应的分表添加的列默认值为 -1,但下游最终结构希望默认值为 0。 5. DM-worker 接受到 `mysql-replica-02` 分表的 DDL 之后,将对应的 DDL 信息发送给 DM-master,DM-master 无法生成兼容表结构,MySQL-2 上的同步暂停。此时使用 `shard-ddl-lock` 和 `query-status test` 命令可以查到具体问题: @@ -625,9 +624,7 @@ MySQL 及 DM 操作与处理流程如下: ... ``` -6. DM-master 上 ID 为 ```test-`shardddl`.`tb` ``` 的 lock 无法为 `mysql-replica-02` 上的 `shardddl1`.`tb1` 的 DDL 生成兼容表结构, - -`shard-ddl-lock` 返回的 `unsynced` 中一直包含 `mysql-replica-02` 的信息。 +6. DM-master 上 ID 为 ```test-`shardddl`.`tb` ``` 的 lock 无法为 `mysql-replica-02` 上的 `shardddl1`.`tb1` 的 DDL 生成兼容表结构,`shard-ddl-lock` 返回的 `unsynced` 中一直包含 `mysql-replica-02` 的信息。 7. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 该 DDL lock。 From 4d9bcf4b0c21dabe0e20947fdad29500ea442570 Mon Sep 17 00:00:00 2001 From: Chunzhu Li Date: Thu, 5 May 2022 20:59:41 +0800 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Ran --- dm/manually-handling-sharding-ddl-locks.md | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/dm/manually-handling-sharding-ddl-locks.md b/dm/manually-handling-sharding-ddl-locks.md index c7bb0715e86b..1c4a509af38f 100644 --- a/dm/manually-handling-sharding-ddl-locks.md +++ b/dm/manually-handling-sharding-ddl-locks.md @@ -5,10 +5,12 @@ aliases: ['/docs-cn/tidb-data-migration/dev/manually-handling-sharding-ddl-locks # 手动处理 Sharding DDL Lock -DM (Data Migration) 目前存在[悲观模式](/dm/feature-shard-merge-pessimistic.md)与[乐观模式](/dm/feature-shard-merge-optimistic.md)两种分库分表合并迁移模式,这两种模式中均存在 `shard-ddl-lock` 的概念,但是其实际作用略有不同。 +在分库分表合并迁移发生异常时,你需要使用 `shard-ddl-lock` 命令手动处理 sharding DDL lock。 -1. 在悲观模式中,DM 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。绝大多数情况下,该锁定机制可自动完成;但在部分异常情况发生时,需要使用 `shard-ddl-lock` 手动处理异常的 DDL lock。 -2. 在乐观模式中,DM 使用表结构与 DDL 信息来确保分库分表的 DDL 操作可以正确执行。sharding DDL Lock 在乐观模式中用于表示是否所有分表可以生成兼容表结构。绝大多数情况不需人为干预,仅当分库分表表结构存在不可解冲突时,才可以使用 `shard-ddl-lock` 手动处理异常表结构。 +在 DM 中有[悲观模式](/dm/feature-shard-merge-pessimistic.md)与[乐观模式](/dm/feature-shard-merge-optimistic.md)两种分库分表合并迁移模式。两种模式中的`shard-ddl-lock` 的概念存在差异: + +- 在悲观模式中,DM 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。绝大多数情况下,该锁定机制可自动完成;但在部分异常情况发生时,需要使用 `shard-ddl-lock` 手动处理异常的 DDL lock。 +- 在乐观模式中,DM 使用表结构与 DDL 信息来确保分库分表的 DDL 操作可以正确执行。sharding DDL Lock 在乐观模式中用于表示是否所有分表可以生成兼容表结构。绝大多数情况不需人为干预,仅当分库分表表结构存在不可解冲突时,才需要使用 `shard-ddl-lock` 手动处理异常表结构。 > **注意:** > @@ -470,7 +472,7 @@ MySQL 及 DM 操作与处理流程如下: #### Lock 异常原因 -在 DM-master 尝试自动协调乐观 DDL,需要等待所有 MySQL source 的表结构达到一致状态,锁信息才会被清除(详见[乐观分表合并协调原理](/dm/feature-shard-merge-optimistic.md#原理))。如果 sharding DDL 在迁移过程中出现分表的 DDL 生成了不一致表结构,例如部分分表添加 default 0 的列而部分添加 default 1 的列,将造成 master 无法生成兼容表结构从而使得 lock 无法自动 unlock。 +在 DM-master 尝试自动协调乐观 DDL,需要等待所有 MySQL source 的表结构达到一致状态,锁信息才会被清除(详见[乐观分表合并协调原理](/dm/feature-shard-merge-optimistic.md#原理))。如果 sharding DDL 在迁移过程中出现分表的 DDL 生成了不一致表结构,例如部分分表添加 default 0 的列而部分添加 default 1 的列,将造成 DM-master 无法生成兼容表结构,从而使得锁无法自动 unlock。 #### 手动处理示例 @@ -628,22 +630,24 @@ MySQL 及 DM 操作与处理流程如下: 7. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 该 DDL lock。 - - 在乐观模式执行 `shard-ddl-lock unlock` 时需要指定 `-s,-d,-t` 为上文中的 `blockDDLOwner` 中的信息,每个参数均需要且仅指定一个值。 - - 当存在任意 MySQL source 报错时,`result` 将为 `false`,此时请仔细检查各 MySQL source 的错误是否是预期可接受的。 + 执行 `shard-ddl-lock unlock` 命令。根据第 5 步中 `query-status` 命令输出中的 `blockDDLOwner` 信息,指定 `-s`、`-d`、`-t` 这三个参数,每个参数有且仅有一个值。 - {{< copyable "shell-regular" >}} + {{< copyable "shell-regular" >}} - ```bash - shard-ddl-lock unlock 'test-`shardddl`.`tb`' -s mysql-replica-02 -d shardddl1 -t tb1 --action skip - ``` + ```bash + shard-ddl-lock unlock 'test-`shardddl`.`tb`' -s mysql-replica-02 -d shardddl1 -t tb1 --action skip + ``` - ``` - { - "result": true, - "msg": "" - ``` + ``` + { + "result": true, + "msg": "" + } + ``` + + 当存在任意 MySQL source 报错时,`result` 将为 `false`,此时请仔细检查各 MySQL source 的错误是否是预期可接受的。 -8. 重复该操作跳过第二个分表的 DDL。 +8. 重复第 7 步,跳过第二个分表的 DDL。 9. 使用 `shard-ddl-lock` 确认 DDL lock 是否被成功 unlock。 ```bash From 298fff88acc98cac9dd1c7c219bcd2e4466d9c83 Mon Sep 17 00:00:00 2001 From: Chunzhu Li Date: Thu, 5 May 2022 21:14:32 +0800 Subject: [PATCH 4/6] fix --- dm/manually-handling-sharding-ddl-locks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dm/manually-handling-sharding-ddl-locks.md b/dm/manually-handling-sharding-ddl-locks.md index 1c4a509af38f..0d67eb9751d2 100644 --- a/dm/manually-handling-sharding-ddl-locks.md +++ b/dm/manually-handling-sharding-ddl-locks.md @@ -138,8 +138,8 @@ shard-ddl-lock test 用于主动请求 DM-master 解除指定的 DDL lock。 -1. 悲观模式 `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 -2. 乐观模式 `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 +1. [悲观模式](/dm/feature-shard-merge-pessimistic.md) `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 +2. [乐观模式](/dm/feature-shard-merge-optimistic.md) `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 > **注意:** > From 3e398cf24e7466ecf5152a83ffeaceffe250efe2 Mon Sep 17 00:00:00 2001 From: Ran Date: Fri, 6 May 2022 18:50:51 +0800 Subject: [PATCH 5/6] refine wording; use simpletab Signed-off-by: Ran --- dm/manually-handling-sharding-ddl-locks.md | 61 +++++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/dm/manually-handling-sharding-ddl-locks.md b/dm/manually-handling-sharding-ddl-locks.md index 0d67eb9751d2..3722bfdcbbea 100644 --- a/dm/manually-handling-sharding-ddl-locks.md +++ b/dm/manually-handling-sharding-ddl-locks.md @@ -138,12 +138,14 @@ shard-ddl-lock test 用于主动请求 DM-master 解除指定的 DDL lock。 -1. [悲观模式](/dm/feature-shard-merge-pessimistic.md) `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 -2. [乐观模式](/dm/feature-shard-merge-optimistic.md) `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 - > **注意:** > -> `shard-ddl-lock unlock` 在 DM v6.0 以前版本仅对悲观协调模式 (`pessimistic`) 下产生的 lock 有效。 +> 在 DM v6.0 以前版本,`shard-ddl-lock unlock` 仅对悲观协调模式 (`pessimistic`) 下产生的 lock 有效。 + + +
+ +[悲观模式](/dm/feature-shard-merge-pessimistic.md) `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 {{< copyable "shell-regular" >}} @@ -184,7 +186,37 @@ Global Flags: - 非 flag 参数,string,必选 - 指定需要执行 unlock 操作的 DDL lock ID(即 `shard-ddl-lock` 返回结果中的 `ID`) -乐观模式相关参数 +
+ +
+ +[乐观模式](/dm/feature-shard-merge-optimistic.md) `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 + +{{< copyable "shell-regular" >}} + +```bash +shard-ddl-lock unlock -h +``` + +``` +Unlock un-resolved DDL locks forcely + +Usage: + dmctl shard-ddl-lock unlock [flags] + +Flags: + -a, --action string accept skip/exec values which means whether to skip or execute ddls (default "skip") + -d, --database string database name of the table + -f, --force-remove force to remove DDL lock + -h, --help help for unlock + -o, --owner string source to replace the default owner + -t, --table string table name + +Global Flags: + -s, --source strings MySQL Source ID. +``` + +乐观模式相关参数: + `-a, --action`: - flag 参数,string,可选 @@ -207,6 +239,9 @@ Global Flags: - 非 flag 参数,string,必选 - 指定需要执行 unlock 操作的 DDL lock ID(即 `shard-ddl-lock` 返回结果中的 `ID`) +
+
+ 以下是一个使用 `shard-ddl-lock unlock` 命令的示例: {{< copyable "shell-regular" >}} @@ -476,7 +511,7 @@ MySQL 及 DM 操作与处理流程如下: #### 手动处理示例 -假设上游有 MySQL-1(`mysql-replica-01`)和 MySQL-2(`mysql-replica-02`)两个实例,其中 MySQL-1 中有 `shardddl1`.`tb1` 一个表,MySQL-2 中有 `shardddl1`.`tb1` 和 `shardddl1`.`tb2` 两个表。现在需要将这 3 个表合并后迁移到下游 TiDB 的 `shardddl`.`tb` 表中。 +假设上游有 MySQL-1 (`mysql-replica-01`) 和 MySQL-2 (`mysql-replica-02`) 两个实例,其中 MySQL-1 中有 `shardddl1`.`tb1` 一个表,MySQL-2 中有 `shardddl1`.`tb1` 和 `shardddl1`.`tb2` 两个表。现在需要将这三个表合并后迁移到下游 TiDB 的 `shardddl`.`tb` 表中。 初始表结构如下: @@ -524,7 +559,7 @@ MySQL 及 DM 操作与处理流程如下: ALTER TABLE shardddl1.tb1 MODIFY b INT DEFAULT 0; ``` -2. DM-worker 接受到 `mysql-replica-01` 分表的 DDL 之后,将对应的 DDL 信息发送给 DM-master,DM-master 创建相应的 DDL lock。 +2. DM-worker 接收到 `mysql-replica-01` 分表的 DDL 之后,将对应的 DDL 信息发送给 DM-master,DM-master 创建相应的 DDL lock。 3. 使用 `shard-ddl-lock` 查看当前的 DDL lock 信息。 {{< copyable "shell-regular" >}} @@ -566,6 +601,9 @@ MySQL 及 DM 操作与处理流程如下: shard-ddl-lock test ``` +
+ 期望输出 + ``` { "result": true, @@ -591,10 +629,15 @@ MySQL 及 DM 操作与处理流程如下: } ``` +
+ ```bash query-status test ``` +
+ 期望输出 + ``` ... { @@ -626,6 +669,8 @@ MySQL 及 DM 操作与处理流程如下: ... ``` +
+ 6. DM-master 上 ID 为 ```test-`shardddl`.`tb` ``` 的 lock 无法为 `mysql-replica-02` 上的 `shardddl1`.`tb1` 的 DDL 生成兼容表结构,`shard-ddl-lock` 返回的 `unsynced` 中一直包含 `mysql-replica-02` 的信息。 7. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 该 DDL lock。 @@ -697,4 +742,4 @@ MySQL 及 DM 操作与处理流程如下: > **注意:** > -> 在某些场景下 `shard-ddl-lock unlock` 时,如果下游不进行手动处理,可能会引起上下游数据不一致。 +> 在某些场景下运行 `shard-ddl-lock unlock` 时,如果下游不进行手动处理,可能会引起上下游数据不一致。 From cc2a4261772a99c71864d803986d6e93405d33a9 Mon Sep 17 00:00:00 2001 From: Ran Date: Wed, 15 Jun 2022 11:15:41 +0800 Subject: [PATCH 6/6] refine wording; fix typos Signed-off-by: Ran --- dm/manually-handling-sharding-ddl-locks.md | 60 ++++++++++++---------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/dm/manually-handling-sharding-ddl-locks.md b/dm/manually-handling-sharding-ddl-locks.md index 3722bfdcbbea..9c701f290063 100644 --- a/dm/manually-handling-sharding-ddl-locks.md +++ b/dm/manually-handling-sharding-ddl-locks.md @@ -7,7 +7,7 @@ aliases: ['/docs-cn/tidb-data-migration/dev/manually-handling-sharding-ddl-locks 在分库分表合并迁移发生异常时,你需要使用 `shard-ddl-lock` 命令手动处理 sharding DDL lock。 -在 DM 中有[悲观模式](/dm/feature-shard-merge-pessimistic.md)与[乐观模式](/dm/feature-shard-merge-optimistic.md)两种分库分表合并迁移模式。两种模式中的`shard-ddl-lock` 的概念存在差异: +在 DM 中有[悲观模式](/dm/feature-shard-merge-pessimistic.md)与[乐观模式](/dm/feature-shard-merge-optimistic.md)两种分库分表合并迁移模式。两种模式中的 `shard-ddl-lock` 的概念存在差异: - 在悲观模式中,DM 使用 sharding DDL lock 来确保分库分表的 DDL 操作可以正确执行。绝大多数情况下,该锁定机制可自动完成;但在部分异常情况发生时,需要使用 `shard-ddl-lock` 手动处理异常的 DDL lock。 - 在乐观模式中,DM 使用表结构与 DDL 信息来确保分库分表的 DDL 操作可以正确执行。sharding DDL Lock 在乐观模式中用于表示是否所有分表可以生成兼容表结构。绝大多数情况不需人为干预,仅当分库分表表结构存在不可解冲突时,才需要使用 `shard-ddl-lock` 手动处理异常表结构。 @@ -82,7 +82,7 @@ shard-ddl-lock test "task": "test", # lock 所属的任务名 "mode": "pessimistic" # shard DDL 协调模式,可为悲观模式 "pessimistic" 或乐观模式 "optimistic" "owner": "mysql-replica-01", # lock 的 owner,在悲观模式时为第一个遇到该 DDL 的 source ID - "DDLs": [ # 在悲观模式时为 lock 对应的 DDL 列表,在乐观模式时总为空 + "DDLs": [ # 在悲观模式时为 lock 对应的 DDL 列表 "USE `shard_db`; ALTER TABLE `shard_db`.`shard_table` DROP COLUMN `c2`;" ], "synced": [ # 已经收到对应 MySQL 实例内所有分表 DDL 的 source 列表 @@ -145,7 +145,11 @@ shard-ddl-lock test
-[悲观模式](/dm/feature-shard-merge-pessimistic.md) `unlock` 包括操作:请求 owner 执行 DDL 操作,请求其他非 owner 的 DM-worker 跳过 DDL 操作,移除 DM-master 上的 lock 信息。 +[悲观模式](/dm/feature-shard-merge-pessimistic.md) `unlock` 包括以下操作: + +* 请求 owner 执行 DDL 操作。 +* 请求其他非 owner 的 DM-worker 跳过 DDL 操作。 +* 移除 DM-master 上的 lock 信息。 {{< copyable "shell-regular" >}} @@ -190,7 +194,11 @@ Global Flags:
-[乐观模式](/dm/feature-shard-merge-optimistic.md) `unlock` 包括操作:请求指定的处于冲突状态的上游表 执行/跳过 冲突 DDL 操作,对其他非指定的表不会进行任何操作,若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 +[乐观模式](/dm/feature-shard-merge-optimistic.md) `unlock` 包括以下操作: + +* 请求指定的处于冲突状态的上游表执行或跳过冲突 DDL 操作。 +* 对其他非指定的表不会进行任何操作。 +* 若操作后 DM-master 可以为所有分表生成兼容表结构,则 DM-master 上的 lock 信息将被自动移除。 {{< copyable "shell-regular" >}} @@ -225,15 +233,15 @@ Global Flags: + `-s, --source`: - flag 参数,string,乐观模式必填且目前只支持写一个 - - 执行需要执行 unlock 操作的上游的 source ID,可通过 `shard-ddl-lock` 命令获取 + - 指定需要执行 unlock 操作的上游的 source ID,可通过 `shard-ddl-lock` 命令获取 + `-d, --database`: - flag 参数,string,乐观模式必填且目前只支持写一个 - - 执行需要执行 unlock 操作的上游的数据库名称,可通过 `shard-ddl-lock` 命令获取 + - 指定需要执行 unlock 操作的上游的数据库名称,可通过 `shard-ddl-lock` 命令获取 + `-t, --table`: - flag 参数,string,乐观模式必填且目前只支持写一个 - - 执行需要执行 unlock 操作的上游的表名称,可通过 `shard-ddl-lock` 命令获取 + - 指定需要执行 unlock 操作的上游的表名称,可通过 `shard-ddl-lock` 命令获取 + `lock-id`: - 非 flag 参数,string,必选 @@ -507,7 +515,7 @@ MySQL 及 DM 操作与处理流程如下: #### Lock 异常原因 -在 DM-master 尝试自动协调乐观 DDL,需要等待所有 MySQL source 的表结构达到一致状态,锁信息才会被清除(详见[乐观分表合并协调原理](/dm/feature-shard-merge-optimistic.md#原理))。如果 sharding DDL 在迁移过程中出现分表的 DDL 生成了不一致表结构,例如部分分表添加 default 0 的列而部分添加 default 1 的列,将造成 DM-master 无法生成兼容表结构,从而使得锁无法自动 unlock。 +在 DM-master 尝试自动协调乐观 DDL,需要等待所有 MySQL source 的表结构达到一致状态,锁信息才会被清除(详见[乐观分表合并协调原理](/dm/feature-shard-merge-optimistic.md#原理))。在 sharding DDL 迁移过程中,如果分表的 DDL 生成了不一致的表结构,例如部分分表添加 default 0 的列、而另一部分分表添加 default 1 的列,将造成 DM-master 无法生成兼容表结构,从而使得锁无法自动 unlock。 #### 手动处理示例 @@ -673,7 +681,7 @@ MySQL 及 DM 操作与处理流程如下: 6. DM-master 上 ID 为 ```test-`shardddl`.`tb` ``` 的 lock 无法为 `mysql-replica-02` 上的 `shardddl1`.`tb1` 的 DDL 生成兼容表结构,`shard-ddl-lock` 返回的 `unsynced` 中一直包含 `mysql-replica-02` 的信息。 -7. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 该 DDL lock。 +7. 使用 `shard-ddl-lock unlock` 来请求 DM-master 主动 unlock 第一个分表 (`shardddl1`.`tb1`) 的 DDL lock。 执行 `shard-ddl-lock unlock` 命令。根据第 5 步中 `query-status` 命令输出中的 `blockDDLOwner` 信息,指定 `-s`、`-d`、`-t` 这三个参数,每个参数有且仅有一个值。 @@ -692,7 +700,7 @@ MySQL 及 DM 操作与处理流程如下: 当存在任意 MySQL source 报错时,`result` 将为 `false`,此时请仔细检查各 MySQL source 的错误是否是预期可接受的。 -8. 重复第 7 步,跳过第二个分表的 DDL。 +8. 重复第 7 步,unlock 第二个分表 (`shardddl1`.`tb2`) 的 DDL lock。 9. 使用 `shard-ddl-lock` 确认 DDL lock 是否被成功 unlock。 ```bash @@ -712,21 +720,21 @@ MySQL 及 DM 操作与处理流程如下: {{< copyable "sql" >}} - ```sql - SHOW CREATE TABLE shardddl.tb; - ``` - - ``` - +-------------+--------------------------------------------------+ - | Table | Create Table | - +-------------+--------------------------------------------------+ - | tb | CREATE TABLE `tb` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT '0', - PRIMARY KEY (`a`) - ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin - +-------------+--------------------------------------------------+ - ``` + ```sql + SHOW CREATE TABLE shardddl.tb; + ``` + + ``` + +-------------+--------------------------------------------------+ + | Table | Create Table | + +-------------+--------------------------------------------------+ + | tb | CREATE TABLE `tb` ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT '0', + PRIMARY KEY (`a`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin + +-------------+--------------------------------------------------+ + ``` 11. 使用 `query-status` 确认迁移任务是否正常。 @@ -737,7 +745,7 @@ MySQL 及 DM 操作与处理流程如下: 因此,在手动解锁 DDL lock 后,需要再执行以下操作: 1. 使用 `pause-task` 暂停运行中的任务。 -2. 使用 `binlog-schema update` 更新 skip 的表的表结构为兼容的表结构。 +2. 使用 `binlog-schema update` 更新跳过的分表的表结构为兼容的表结构。 3. 使用 `resume-task` 恢复任务运行。 > **注意:**