# TiCDC 4.0 内部默认使用 old value 测试说明 ###### 注意: 这是一个易用性的改善,并不是一个 feature ## :memo: 落地过程 ### 1. 需求来源 首先是来自 Jira 的 [ticket](https://internal.pingcap.net/jira/projects/DP/issues/DP-71?filter=allissues)。但是当我们做完之后发现其实很早就有一个 [GitHub Issue](https://github.com/pingcap/ticdc/issues/2073) 提了这个需求。 在该 ticket 中描述了用户使用上的问题: - 从技术上来说,开了 new collation 就必须要开 old value 才能正确同步 - 这个限制是靠用户手动保证的,这种保证极其不可靠 并且还提出了对应需要改善的目标: - 不让用户操心什么是 new collation,和 old value 有什么关系,如果检查到某张表开启 new collation,就自动以开了 old value 的模式去拉 tikv 数据 - 如果用户在配置上没有开启old value,那么希望 cdc 对下游的输出也是没有 old value 的 **注意:如果一个表使用了 new collation,那么它对应的 index 编排方式会发生改变,导致无法通过变更后的 new value 所在 key 反向解析到原数据是怎么样的,导致 TiCDC 无法还原对应的 SQL,最终导致同步失败,所以如果开启了 new collation 那么就需要开启 old value 来拉去 TiKV 数据。** ### 2. 需求演变 在需求的讨论过程中,我们发现在 TiCDC 内部中去判断某张表是否开启 new collation 然后再对应使用开启 old value 的模式去拉数据这个机制非常的复杂。==所以讨论决定无论开不开启 new collation 我们都需要使用开启 old value 的模式去拉数据。== 对于第二个目标没有调整,在用户没有开启 old value 配置时,我们需要保证输出不发生变化。 最终将需求确认好后,创建了对应的 [GitHub Issue](https://github.com/pingcap/ticdc/issues/2301)。 ### 3. 提交 PR 落地 提交 [PR](https://github.com/pingcap/ticdc/pull/2271) 来支持内部总是使用开启 old value 模式来拉 TiKV 的数据。实现该功能过程中,遇到的最核心的问题就是:==用户在没有开启 old value 配置时,我们需要保持输出数据的格式不发生变化== 首先我们需要明确在开启 old value 和不开启 old value 模式时原来的 TiCDC 的行为: | | 开启 old value | 不开启 old value | | -------- | ---------------------------- | ------------------------------------------------------------------------------------------------------ | | 更新数据 | 输出旧的值和新的值 | 只输出新的值,但是如果修改的是 handle key 的列,那么我们需要将更新事件拆分成一个删除事件和一个插入事件 | | 删除数据 | 输出被删除的行数据中的所有列 | 只输出被删除数据的 handle key 的列 | 具体的可以参考 [TiCDC Open Protocol](https://docs.pingcap.com/zh/tidb/stable/ticdc-open-protocol) 的说明。**注意:该说明中对不开启 old value 的更新事件的说明不够仔细。** ### 4. 测试 PR 首先明确我当时做测试主要测试的两个目标: 1. 在不开启 old vlaue 配置时输出和修改之前行为一致 2. 在数据库开启 new collation 之后,在不开启 old value 时也能正确同步数据 所以我在 PR 上做了如下测试: 测试用到的 sql 如下: ```sql CREATE DATABASE `tidb_test` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;; USE `tidb_test`; CREATE TABLE t( id varchar(20) charset utf8mb4 collate utf8mb4_general_ci, name varchar(20) charset utf8mb4 collate utf8mb4_general_ci, age int, primary key(id, name)); INSERT INTO t VALUES ('AA', 'he', 10); INSERT INTO t VALUES ('BB', 'le', 20); INSERT INTO t VALUES ('CC', 'me', 30); DELETE FROM t WHERE `id` = 'AA'; UPDATE t SET id='FF' WHERE age=30; UPDATE t SET age=55 WHERE id='BB'; ``` 测试的用例: - 不开启 new collation - 开启 old value 配置,对比插入、删除、更新的输入是否与旧的 TiCDC 对齐。 - 不开启 old vlaue 配置,对比插入、删除、更新的输入是否与旧的 TiCDC 对齐。 - 开启 new collation - 开启 old value 配置,对比插入、删除、更新的输入是否与旧的 TiCDC 对齐。 - 不开启 old vlaue 配置,对比插入、删除、更新的输入是否与旧的 TiCDC 对齐(旧的 TiCDC 不能正常同步数据,新的可以)。 根据以上的用例,我进行了以下的测试: [不开启 new collation](https://github.com/pingcap/ticdc/pull/2271#issuecomment-880028158) [开启 new collation](https://github.com/pingcap/ticdc/pull/2271#issuecomment-880325935) 我的基本测试步骤: 1. 根据配置启动集群 2. 启动 cdc server (把日志级别修改到 debug) 3. 创建changefeed `./cdc cli changefeed create --sink-uri="blackhole://" --changefeed-id="test"` 4. mysql --host 127.0.0.1 --port 4000 -u root -p --comments < tidb_test.sql 5. grep "BlockHoleSink: EmitRowChangedEvents" ticdc.log 查看数据输出并进行比对。 ------ 4.0 的 PR:https://github.com/pingcap/ticdc/pull/2322 5.0 的 PR:https://github.com/pingcap/ticdc/pull/2323 5.1 的 PR:https://github.com/pingcap/ticdc/pull/2324 注意:TiCDC 从 5.0 以后默认开启 old value。