# 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。