diff --git a/TOC.md b/TOC.md index 71323e5c87fa..5b1baca6994c 100644 --- a/TOC.md +++ b/TOC.md @@ -561,7 +561,7 @@ - [双向复制](/ticdc/ticdc-bidirectional-replication.md) - [单行数据正确性校验](/ticdc/ticdc-integrity-check.md) - [主从集群一致性读和数据校验](/ticdc/ticdc-upstream-downstream-check.md) - - [TiCDC 行为变更说明](/ticdc/ticdc-behavior-change.md) + - [拆分 UPDATE 事件行为说明](/ticdc/ticdc-split-update-behavior.md) - 监控告警 - [基本监控指标](/ticdc/ticdc-summary-monitor.md) - [详细监控指标](/ticdc/monitor-ticdc.md) diff --git a/releases/release-6.5.10.md b/releases/release-6.5.10.md index b9db14aea7fb..4dccd4ba4fbe 100644 --- a/releases/release-6.5.10.md +++ b/releases/release-6.5.10.md @@ -13,7 +13,7 @@ TiDB 版本:6.5.10 ## 兼容性变更 -- 在之前的版本中,TiCDC 在处理包含 `UPDATE` 变更的事务时,如果事件的主键或者非空唯一索引的列值发生改变,则会将该条事件拆分为 `DELETE` 和 `INSERT` 两条事件。从 v6.5.10 开始,当使用 MySQL Sink 时,如果 `UPDATE` 变更所在事务的 `commitTS` 小于对应表开始向下游同步数据时从 PD 获取的当前时间戳 `thresholdTS`,TiCDC 就会将该 `UPDATE` 事件拆分为 `DELETE` 和 `INSERT` 两条事件,然后写入 Sorter 模块。该行为变更解决了由于 TiCDC 接收到的 `UPDATE` 事件顺序可能不正确,导致拆分后的 `DELETE` 和 `INSERT` 事件顺序也可能不正确,从而引发下游数据不一致的问题。更多信息,请参考[用户文档](https://docs.pingcap.com/zh/tidb/v6.5/ticdc-behavior-change#mysql-sink)。[#10918](https://github.com/pingcap/tiflow/issues/10918) @[lidezhu](https://github.com/lidezhu) +- 在之前的版本中,TiCDC 在处理包含 `UPDATE` 变更的事务时,如果事件的主键或者非空唯一索引的列值发生改变,则会将该条事件拆分为 `DELETE` 和 `INSERT` 两条事件。从 v6.5.10 开始,当使用 MySQL Sink 时,如果 `UPDATE` 变更所在事务的 `commitTS` 小于对应表开始向下游同步数据时从 PD 获取的当前时间戳 `thresholdTS`,TiCDC 就会将该 `UPDATE` 事件拆分为 `DELETE` 和 `INSERT` 两条事件,然后写入 Sorter 模块。该行为变更解决了由于 TiCDC 接收到的 `UPDATE` 事件顺序可能不正确,导致拆分后的 `DELETE` 和 `INSERT` 事件顺序也可能不正确,从而引发下游数据不一致的问题。更多信息,请参考[用户文档](https://docs.pingcap.com/zh/tidb/v6.5/ticdc-split-update-behavior#mysql-sink-拆分-update-事件行为说明)。[#10918](https://github.com/pingcap/tiflow/issues/10918) @[lidezhu](https://github.com/lidezhu) - 使用 TiDB Lightning 的严格格式 `strict-format` 导入 CSV 文件时,必须设置行分隔符 [#37338](https://github.com/pingcap/tidb/issues/37338) @[lance6716](https://github.com/lance6716) ## 改进提升 diff --git a/releases/release-6.5.3.md b/releases/release-6.5.3.md index 483ab44407e8..bf90af706dc4 100644 --- a/releases/release-6.5.3.md +++ b/releases/release-6.5.3.md @@ -15,7 +15,7 @@ TiDB 版本:6.5.3 ### 行为变更 -- TiCDC 在处理 Update 事件时,如果事件的主键或者非空唯一索引的列值发生改变,则会将该条事件拆分为 Delete 和 Insert 两条事件。更多信息,请参考[用户文档](/ticdc/ticdc-behavior-change.md#含有单条-update-变更的事务拆分)。 +- TiCDC 在处理 Update 事件时,如果事件的主键或者非空唯一索引的列值发生改变,则会将该条事件拆分为 Delete 和 Insert 两条事件。更多信息,请参考[用户文档](/ticdc/ticdc-split-update-behavior.md#含有单条-update-变更的事务拆分)。 ## 改进提升 diff --git a/releases/release-6.5.4.md b/releases/release-6.5.4.md index e30539bab0c3..47fa68f1839d 100644 --- a/releases/release-6.5.4.md +++ b/releases/release-6.5.4.md @@ -18,7 +18,7 @@ TiDB 版本:6.5.4 ### 行为变更 -- 对于包含多条变更的事务,如果 Update 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 Delete 和 Insert 两条事件,并确保将所有事件有序,以保证 Delete 事件在 Insert 事件之前。更多信息,请参考[用户文档](/ticdc/ticdc-behavior-change.md#含有多条-update-变更的事务拆分)。 +- 对于包含多条变更的事务,如果 Update 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 Delete 和 Insert 两条事件,并确保将所有事件有序,以保证 Delete 事件在 Insert 事件之前。更多信息,请参考[用户文档](/ticdc/ticdc-split-update-behavior.md#含有多条-update-变更的事务拆分)。 ## 改进提升 diff --git a/releases/release-7.1.1.md b/releases/release-7.1.1.md index 16c5a6a92084..31ed866ff65b 100644 --- a/releases/release-7.1.1.md +++ b/releases/release-7.1.1.md @@ -17,7 +17,7 @@ TiDB 版本:7.1.1 ### 行为变更 -- TiCDC 在处理 Update 事件时,如果事件的主键或者非空唯一索引的列值发生改变,则会将该条事件拆分为 Delete 和 Insert 两条事件。更多信息,请参考[用户文档](/ticdc/ticdc-behavior-change.md#含有单条-update-变更的事务拆分)。 +- TiCDC 在处理 Update 事件时,如果事件的主键或者非空唯一索引的列值发生改变,则会将该条事件拆分为 Delete 和 Insert 两条事件。更多信息,请参考[用户文档](/ticdc/ticdc-split-update-behavior.md#含有单条-update-变更的事务拆分)。 ## 改进提升 diff --git a/releases/release-7.1.2.md b/releases/release-7.1.2.md index 3357fb0d7968..f0aee6fd768b 100644 --- a/releases/release-7.1.2.md +++ b/releases/release-7.1.2.md @@ -22,7 +22,7 @@ TiDB 版本:7.1.2 ### 行为变更 -- 对于包含多条变更的事务,如果 Update 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 Delete 和 Insert 两条事件,并确保将所有事件有序,以保证 Delete 事件在 Insert 事件之前。更多信息,请参考[用户文档](/ticdc/ticdc-behavior-change.md#含有多条-update-变更的事务拆分)。 +- 对于包含多条变更的事务,如果 Update 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 Delete 和 Insert 两条事件,并确保将所有事件有序,以保证 Delete 事件在 Insert 事件之前。更多信息,请参考[用户文档](/ticdc/ticdc-split-update-behavior.md#含有多条-update-变更的事务拆分)。 ## 改进提升 diff --git a/ticdc/ticdc-behavior-change.md b/ticdc/ticdc-behavior-change.md deleted file mode 100644 index cbf451ea251b..000000000000 --- a/ticdc/ticdc-behavior-change.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: TiCDC 行为变更说明 -summary: 介绍 TiCDC changefeed 的行为变更,说明变更原因以及影响范围。 ---- - -# TiCDC 行为变更说明 - -## 将 Update 事件拆分为 Delete 和 Insert 事件 - -### 含有单条 Update 变更的事务拆分 - -从 v6.5.3 和 v7.1.1 开始,使用非 MySQL Sink 时,对于仅包含一条 Update 变更的事务,如果 Update 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该条事件拆分为 Delete 和 Insert 两条事件。详情见 GitHub issue [#9086](https://github.com/pingcap/tiflow/issues/9086)。 - -该变更主要为了解决如下问题: - -* 在使用 CSV 和 AVRO 协议时,仅输出新值而不输出旧值。因此,当主键或者非空唯一索引的列值发生改变时,消费者只能接收到变化后的新值,无法得到旧值,导致无法处理变更前的值(例如删除旧值)。 -* 在使用 Index value dispatcher 将数据按照 Key 分发到不同的 Kafka partition 时,下游的消费者组内多个消费者进程独立消费 Kafka Topic partition,由于消费进度不同,可能导致数据不一致的问题。 - -以如下 SQL 为例: - -```sql -CREATE TABLE t (a INT PRIMARY KEY, b INT); -INSERT INTO t VALUES (1, 1); -UPDATE t SET a = 2 WHERE a = 1; -``` - -在上述示例中,主键 `a` 的值从 `1` 修改为 `2`。如果不将该 Update 事件进行拆分: - -* 在使用 CSV 和 AVRO 协议时,消费者仅能看到新值 `a = 2`,而无法得到旧值 `a = 1`。这可能导致下游消费者只插入了新值 `2`,而没有删除旧值 `1`。 -* 在使用 Index value dispatcher 时,插入记录 `(1, 1)` 的事件可能被发送到 Partition 0,而变更事件 `(2, 1)` 可能被发送到 Partition 1。如果 Partition 1 的消费进度快于 Partition 0,则可能由于下游数据系统中找不到相应数据而导致出错。因此,TiCDC 会将该条 Update 事件拆分为 Delete 和 Insert 两条事件,其中,删除记录 `(1, 1)` 被发送到 Partition 0,写入记录 `(2, 1)` 被发送到 Partition 1,以确保无论消费者的进度如何,事件都能被消费成功。 - -### 含有多条 Update 变更的事务拆分 - -从 v6.5.4 和 v7.1.2 开始,对于一个含有多条变更的事务,如果 Update 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 Delete 和 Insert 两条事件,并确保所有事件按照 Delete 事件在 Insert 事件之前的顺序进行排序。详情见 GitHub issue [#9430](https://github.com/pingcap/tiflow/issues/9430)。 - -该变更主要为了解决当使用 MySQL Sink 直接将这两条事件写入下游时,可能会出现主键或唯一键冲突的问题,从而导致 changefeed 报错。当使用 Kafka Sink 或其他 Sink 时,如果消费者需要将数据变更写入关系型数据库或进行类似操作,也可能遇到相同问题。 - -以如下 SQL 为例: - -```sql -CREATE TABLE t (a INT PRIMARY KEY, b INT); -INSERT INTO t VALUES (1, 1); -INSERT INTO t VALUES (2, 2); - -BEGIN; -UPDATE t SET a = 3 WHERE a = 1; -UPDATE t SET a = 1 WHERE a = 2; -UPDATE t SET a = 2 WHERE a = 3; -COMMIT; -``` - -在上述示例中,通过执行三条 SQL 语句对两行数据的主键进行交换,但 TiCDC 只会接收到两条 Update 变更事件,即将主键 `a` 从 `1` 变更为 `2`,将主键 `a` 从 `2` 变更为 `1`,如果 MYSQL Sink 直接将这两条 Update 事件写入下游,会出现主键冲突的问题,导致 changefeed 报错。 - -因此,TiCDC 会将这两条事件拆分为四条事件,即删除记录 `(1, 1)` 和 `(2, 2)` 以及写入记录 `(2, 1)` 和 `(1, 2)`。 diff --git a/ticdc/ticdc-changefeed-config.md b/ticdc/ticdc-changefeed-config.md index 4ef5c5e83eea..8746619050ac 100644 --- a/ticdc/ticdc-changefeed-config.md +++ b/ticdc/ticdc-changefeed-config.md @@ -223,6 +223,9 @@ sasl-oauth-grant-type = "client_credentials" # Kafka SASL OAUTHBEARER 认证机制中的 audience。默认值为空。在使用该认证机制时,该参数可选填。 sasl-oauth-audience = "kafka" +# 控制是否输出原始的数据变更事件,默认值为 false,表示当使用非 MySQL Sink 且 `UPDATE` 事件的主键或者非空唯一索引的列值发生改变时,TiCDC 会将该其拆分为 `DELETE` 和 `INSERT` 两条事件,并确保所有事件按照 `DELETE` 事件在 `INSERT` 事件之前的顺序进行排序。设置为 true 时,表示不拆分事件,直接输出原始事件。 +# output-raw-change-event = false + [sink.cloud-storage-config] # 向下游存储服务保存数据变更记录的并发度,默认值为 16。 worker-count = 16 @@ -236,4 +239,6 @@ file-expiration-days = 0 file-cleanup-cron-spec = "0 0 2 * * *" # 上传单个文件的并发数,默认值为 1,表示禁用并发。 flush-concurrency = 1 +# 控制是否输出原始的数据变更事件,默认值为 false,表示当使用非 MySQL Sink 且 `UPDATE` 事件的主键或者非空唯一索引的列值发生改变时,TiCDC 会将该其拆分为 `DELETE` 和 `INSERT` 两条事件,并确保所有事件按照 `DELETE` 事件在 `INSERT` 事件之前的顺序进行排序。设置为 true 时,表示不拆分事件,直接输出原始事件。 +output-raw-change-event = false ``` diff --git a/ticdc/ticdc-open-api-v2.md b/ticdc/ticdc-open-api-v2.md index 3ac819943671..61ff57de409d 100644 --- a/ticdc/ticdc-open-api-v2.md +++ b/ticdc/ticdc-open-api-v2.md @@ -380,6 +380,7 @@ curl -X GET http://127.0.0.1:8300/api/v2/health | `file_expiration_days` | `INT` 类型,文件保留的时长。| | `file_cleanup_cron_spec` | `STRING` 类型,定时清理任务的运行周期,与 crontab 配置兼容,格式为 ` `。| | `flush_concurrency` | `INT` 类型,上传单个文件的并发数。| +| `output_raw_change_event` | `BOOLEAN` 类型,控制使用非 MySQL Sink 时是否输出原始的数据变更事件。| ### 使用样例 diff --git a/ticdc/ticdc-overview.md b/ticdc/ticdc-overview.md index 7b82c112adbb..aad8fbdaa872 100644 --- a/ticdc/ticdc-overview.md +++ b/ticdc/ticdc-overview.md @@ -100,7 +100,7 @@ MySQL binlog 直接记录了上游执行的所有 DML 操作的 SQL 语句。与 TiCDC 会根据收到的这些数据变更信息,适配各个类型的下游来生成合适格式的数据传输给下游。例如,生成 Canal-JSON、Avro 等格式的数据写入 Kafka 中,或者重新转换成 SQL 语句发送给下游的 MySQL 或者 TiDB。 -目前 TiCDC 将数据变更信息适配对应的协议时,对于特定的 `UPDATE` 事件,可能会将其拆成一条 `DELETE` 事件和一条 `INSERT` 事件。详见[将 Update 事件拆分为 Delete 和 Insert 事件](/ticdc/ticdc-behavior-change.md#将-update-事件拆分为-delete-和-insert-事件)。 +目前 TiCDC 将数据变更信息适配对应的协议时,对于特定的 `UPDATE` 事件,可能会将其拆成一条 `DELETE` 事件和一条 `INSERT` 事件。详见 [MySQL Sink 拆分 `UPDATE` 事件行为说明](/ticdc/ticdc-split-update-behavior.md#mysql-sink-拆分-update-事件行为说明)及[非 MySQL Sink 拆分主键或唯一键 `UPDATE` 事件](/ticdc/ticdc-split-update-behavior.md#非-mysql-sink-拆分主键或唯一键-update-事件)。 当下游是 MySQL 或者 TiDB 时,因为 TiCDC 并非直接获取原生上游执行的 DML 语句,而是重新根据数据变更信息来生成 SQL 语句,因此不能保证写入下游的 SQL 语句和上游执行的 SQL 语句完全相同,但会保证最终结果的一致性。 diff --git a/ticdc/ticdc-split-update-behavior.md b/ticdc/ticdc-split-update-behavior.md new file mode 100644 index 000000000000..228df520d7e8 --- /dev/null +++ b/ticdc/ticdc-split-update-behavior.md @@ -0,0 +1,138 @@ +--- +title: TiCDC 拆分 UPDATE 事件行为说明 +summary: 介绍 TiCDC changefeed 拆分 UPDATE 事件的行为变更,说明变更原因以及影响范围。 +aliases: ['/zh/tidb/dev/ticdc-behavior-change'] +--- + +# TiCDC 拆分 UPDATE 事件行为说明 + +## MySQL Sink 拆分 `UPDATE` 事件行为说明 + +从 v6.5.10 开始,当使用 MySQL Sink 时,TiCDC 的任意节点每次收到某张表的同步任务请求并开始向下游同步数据之前,会从 PD 获取当前的时间戳 `thresholdTS`,并根据时间戳的值决定是否拆分对应表的 `UPDATE` 事件: + +- 对于含有单条或多条 `UPDATE` 变更的事务,如果该事务的 `commitTS` 小于 `thresholdTS`,在写入 Sorter 模块之前 TiCDC 会将每条 `UPDATE` 事件拆分为 `DELETE` 和 `INSERT` 两条事件。 +- 对于事务的 `commitTS` 大于或等于 `thresholdTS` 的 `UPDATE` 事件,TiCDC 不会对其进行拆分。详情见 GitHub issue [#10918](https://github.com/pingcap/tiflow/issues/10918)。 + +该行为变更(即根据 `thresholdTS` 决定是否拆分 `UPDATE` 事件)解决了由于 TiCDC 接收到的 `UPDATE` 事件顺序可能不正确,导致拆分后的 `DELETE` 和 `INSERT` 事件顺序也可能不正确,从而引发下游数据不一致的问题。 + +以如下 SQL 为例: + +```sql +CREATE TABLE t (a INT PRIMARY KEY, b INT); +INSERT INTO t VALUES (1, 1); +INSERT INTO t VALUES (2, 2); + +BEGIN; +UPDATE t SET a = 3 WHERE a = 2; +UPDATE t SET a = 2 WHERE a = 1; +COMMIT; +``` + +在该示例中,事务内的两条 `UPDATE` 语句的执行顺序有先后依赖关系,即先将主键 `a` 从 `2` 变更为 `3`,再将主键 `a` 从 `1` 变更为 `2`。执行完该事务后,上游数据库内的记录为 `(2, 1)` 和 `(3, 2)`。 + +但 TiCDC 内部收到的 `UPDATE` 事件顺序可能与上游事务内部实际的执行顺序不同,例如: + +```sql +UPDATE t SET a = 2 WHERE a = 1; +UPDATE t SET a = 3 WHERE a = 2; +``` + +- 在引入该行为变更之前,TiCDC 会将这些 `UPDATE` 事件写入 Sorter 模块之后再将其拆分为 `DELETE` 和 `INSERT` 事件。拆分后下游实际执行的事件顺序如下: + + ```sql + BEGIN; + DELETE FROM t WHERE a = 1; + REPLACE INTO t VALUES (2, 1); + DELETE FROM t WHERE a = 2; + REPLACE INTO t VALUES (3, 2); + COMMIT; + ``` + + 下游执行完该事务后,数据库内的记录为 `(3, 2)`,与上游数据库的记录(即 `(2, 1)` 和 `(3, 2)`)不同,即发生了数据不一致问题。 + +- 在引入该行为变更之后,如果该事务的 `commitTS` 小于对应表开始向下游同步数据时 TiCDC 获取的 `thresholdTS`,TiCDC 会在这些 `UPDATE` 事件写入 Sorter 模块之前将其拆分为 `DELETE` 和 `INSERT` 事件,经过 Sorter 排序后下游实际执行的事件顺序如下: + + ```sql + BEGIN; + DELETE FROM t WHERE a = 1; + DELETE FROM t WHERE a = 2; + REPLACE INTO t VALUES (2, 1); + REPLACE INTO t VALUES (3, 2); + COMMIT; + ``` + + 下游执行完该事务后,下游数据库内的记录和上游数据库一样,都为 `(2, 1)` 和 `(3, 2)`,保证了数据一致性。 + +从该示例中可以看到,在写入 Sorter 模块之前将 `UPDATE` 事件拆分为 `DELETE` 和 `INSERT` 事件,可以保证拆分后所有的 `DELETE` 事件都在 `INSERT` 事件之前执行,这样无论 TiCDC 收到的 `UPDATE` 事件顺序,均可以保证数据一致性。 + +> **注意:** +> +> 该行为变更后,在使用 MySQL Sink 时,TiCDC 在大部分情况下都不会拆分 `UPDATE` 事件,因此 changefeed 在运行时可能会出现主键或唯一键冲突的问题。该问题会导致 changefeed 自动重启,重启后发生冲突的 `UPDATE` 事件会被拆分为 `DELETE` 和 `INSERT` 事件并写入 Sorter 模块中,此时可以确保同一事务内所有事件按照 `DELETE` 事件在 `INSERT` 事件之前的顺序进行排序,从而正确完成数据同步。 + +## 非 MySQL Sink 拆分主键或唯一键 `UPDATE` 事件 + +### 含有单条 `UPDATE` 变更的事务拆分 + +从 v6.5.3、v7.1.1 开始,使用非 MySQL Sink 时,对于仅包含一条 `UPDATE` 变更的事务,如果 `UPDATE` 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该条事件拆分为 `DELETE` 和 `INSERT` 两条事件。详情见 GitHub issue [#9086](https://github.com/pingcap/tiflow/issues/9086)。 + +该变更主要为了解决在使用 CSV 和 AVRO 协议时,TiCDC 在默认配置下仅输出新值而不输出旧值的问题。因此,当主键或者非空唯一索引的列值发生改变时,消费者只能接收到变化后的新值,无法得到旧值,导致无法处理变更前的值(例如删除旧值)。以如下 SQL 为例: + +```sql +CREATE TABLE t (a INT PRIMARY KEY, b INT); +INSERT INTO t VALUES (1, 1); +UPDATE t SET a = 2 WHERE a = 1; +``` + +在上述示例中,主键 `a` 的值从 `1` 修改为 `2`。如果不将该 `UPDATE` 事件进行拆分,在使用 CSV 和 AVRO 协议时,消费者仅能看到新值 `a = 2`,而无法得到旧值 `a = 1`。这可能导致下游消费者只插入了新值 `2`,而没有删除旧值 `1`。 + +### 含有多条 `UPDATE` 变更的事务拆分 + +从 v6.5.4、v7.1.2 开始,对于一个含有多条变更的事务,如果 `UPDATE` 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 `DELETE` 和 `INSERT` 两条事件,并确保所有事件按照 `DELETE` 事件在 `INSERT` 事件之前的顺序进行排序。详情见 GitHub issue [#9430](https://github.com/pingcap/tiflow/issues/9430)。 + +该变更主要为了解决当使用 Kafka Sink 或其他 Sink 时,由于 TiCDC 接收到的 `UPDATE` 事件顺序可能不正确,消费者将数据变更写入关系型数据库或进行类似操作,可能遇到主键或唯一键冲突的问题。 + +以如下 SQL 为例: + +```sql +CREATE TABLE t (a INT PRIMARY KEY, b INT); +INSERT INTO t VALUES (1, 1); +INSERT INTO t VALUES (2, 2); + +BEGIN; +UPDATE t SET a = 3 WHERE a = 1; +UPDATE t SET a = 1 WHERE a = 2; +UPDATE t SET a = 2 WHERE a = 3; +COMMIT; +``` + +在上述示例中,通过执行三条 SQL 语句对两行数据的主键进行交换,但 TiCDC 只会接收到两条 `UPDATE` 变更事件,即将主键 `a` 从 `1` 变更为 `2`,将主键 `a` 从 `2` 变更为 `1`,如果消费者直接将这两条 `UPDATE` 事件写入下游,会出现主键冲突的问题,导致 changefeed 报错。 + +因此,TiCDC 会将这两条事件拆分为四条事件,即删除记录 `(1, 1)` 和 `(2, 2)` 以及写入记录 `(2, 1)` 和 `(1, 2)`。 + +### 控制是否拆分主键或唯一键 `UPDATE` 事件 + +从 v6.5.10、v7.1.6 开始,使用非 MySQL Sink 时,TiCDC 支持通过 `output-raw-change-event` 参数控制是否拆分主键或唯一键 `UPDATE` 事件,详情见 GitHub issue [#11211](https://github.com/pingcap/tiflow/issues/11211)。这个参数的具体行为是: + +- 当 `output-raw-change-event = false` 时,如果 `UPDATE` 事件的主键或者非空唯一索引的列值发生改变,TiCDC 会将该其拆分为 `DELETE` 和 `INSERT` 两条事件,并确保所有事件按照 `DELETE` 事件在 `INSERT` 事件之前的顺序进行排序。 +- 当 `output-raw-change-event = true` 时,TiCDC 不拆分 `UPDATE` 事件。注意,当表的主键为聚簇索引时,对主键的更新会在 TiDB 中拆分为 `DELETE` 和 `INSERT` 两个事件,该行为不受 `output-raw-change-event` 参数的影响。 + +#### Release 6.5 的兼容性 + +| 版本 | 协议 | 拆分主键或唯一键 `UPDATE` 事件 | 不拆分主键或唯一键 `UPDATE` 事件 | 备注 | +| -- | -- | -- | -- | -- | +| <= v6.5.2 | 所有协议 | ✗ | ✓ |  | +| v6.5.3、v6.5.4 | Canal/Open | ✗ | ✓ |  | +| v6.5.3 | CSV/Avro | ✗ | ✗ | 拆分但是不排序, 详见 [#9086](https://github.com/pingcap/tiflow/issues/9658) | +| v6.5.4 | Canal/Open | ✗ | ✗ | 只拆分并排序包含多条变更的事务 | +| v6.5.5 ~ v6.5.9 | 所有协议 | ✓ | ✗ | | +| \>= v6.5.10 | 所有协议 | ✓ (默认值:`output-raw-change-event = false`) | ✓ (可选配置项:`output-raw-change-event = true`) | | + +#### Release 7.1 的兼容性 + +| 版本 | 协议 | 拆分主键或唯一键 `UPDATE` 事件 | 不拆分主键或唯一键 `UPDATE` 事件 | 备注 | +| -- | -- | -- | -- | -- | +| v7.1.0 | 所有协议 | ✗ | ✓ |  | +| v7.1.1 | Canal/Open | ✗ | ✓ |  | +| v7.1.1 | CSV/Avro | ✗ | ✗ | 拆分但是不排序, 详见 [#9086](https://github.com/pingcap/tiflow/issues/9658) | +| v7.1.2 ~ v7.1.5 | 所有协议 | ✓ | ✗ |  | +| \>= v7.1.6(待发布)| 所有协议 | ✓ (默认值:`output-raw-change-event = false`) | ✓ (可选配置项:`output-raw-change-event = true`) | | diff --git a/ticdc/troubleshoot-ticdc.md b/ticdc/troubleshoot-ticdc.md index e0cb6c0dc7ef..941224613069 100644 --- a/ticdc/troubleshoot-ticdc.md +++ b/ticdc/troubleshoot-ticdc.md @@ -139,13 +139,21 @@ fetch.message.max.bytes=2147483648 ## TiCDC 同步时,在下游执行 DDL 语句失败会有什么表现,如何恢复? -如果某条 DDL 语句执行失败,同步任务 (changefeed) 会自动停止,checkpoint-ts 断点时间戳为该条出错 DDL 语句的结束时间戳 (finish-ts) 减去一。如果希望让 TiCDC 在下游重试执行这条 DDL 语句,可以使用 `cdc cli changefeed resume` 恢复同步任务。例如: +如果某条 DDL 语句执行失败,同步任务 (changefeed) 会自动停止,checkpoint-ts 断点时间戳为该条出错 DDL 语句的结束时间戳 (finish-ts)。如果希望让 TiCDC 在下游重试执行这条 DDL 语句,可以使用 `cdc cli changefeed resume` 恢复同步任务。例如: ```shell cdc cli changefeed resume -c test-cf --server=http://127.0.0.1:8300 ``` -如果希望跳过这条出错的 DDL 语句,可以将 changefeed 的 start-ts 设为报错时的 checkpoint-ts 加上一,然后通过 `cdc cli changefeed create` 新建同步任务。假设报错时的 checkpoint-ts 为 `415241823337054209`,可以进行如下操作来跳过该 DDL 语句: +如果希望跳过这条出错的 DDL 语句,可以通过配置 `ignore-txn-start-ts` 参数跳过指定的 `start-ts` 对应的事务。例如: + +1. 首先在 TiCDC 日志中搜寻 `apply job` 字段,确认耗时较长的 DDL 操作的 `start-ts`。 +2. 修改 changefeed 配置,将上述 `start-ts` 添加到 `ignore-txn-start-ts` 配置项中。 +3. 恢复被暂停的 changefeed。 + +> **注意:** +> +> 虽然将 changefeed 的 `start-ts` 设为报错时的 `checkpoint-ts` 值加上 1,然后重建任务也可以跳过该 DDL 语句,但同时会导致 TiCDC 丢失 `checkpointTs+1` 时刻对应的 DML 数据变更。严禁在生产环境执行这样的操作。 ```shell cdc cli changefeed remove --server=http://127.0.0.1:8300 --changefeed-id simple-replication-task