TiCDC 表路由 从 v8.5.7 开始引入
TiCDC 表路由 (Table Routing) 允许你通过 changefeed 配置,将上游表映射到指定的下游库名或表名。该功能仅适用于 TiCDC 新架构,不支持 TiCDC 老架构。
表路由只会改变 TiCDC 输出到下游的库名和表名,不会改变行数据、列名、表结构、表过滤规则、Topic 分发规则、Partition 分发规则或列选择规则。
使用场景
表路由适用于以下场景:
- 将
sales.orders同步到archive.sales_orders,或同步到符合其他下游命名规范的表。 - 将多个源库同步到同一个目标库,并通过保持目标表名唯一区分源库,例如将
tenant_001.orders同步到tenant_mirror.tenant_001_orders。 - 构建迁移、容灾、归档或影子 Changefeed,避免写入与上游同名的下游对象。
- 向 MQ 消费程序或存储服务暴露稳定的库表名。
配置表路由
配置前,请先启用 TiCDC 新架构。详情参见 newarch。
以下示例将 sales.orders 路由到 archive.sales_orders:
[sink]
[[sink.dispatchers]]
matcher = ["sales.orders"]
target-schema = "archive"
target-table = "{schema}_{table}"
Changefeed 启动后,sales.orders 的 DML 和 DDL 事件会写入下游的 archive.sales_orders。
配置字段
你可以通过 sink.dispatchers 的以下字段配置表路由功能。
匹配行为如下:
- 只有设置了
target-schema或target-table的sink.dispatchers规则才会参与表路由。 - 如果一张表匹配多条表路由规则,只有
sink.dispatchers中第一条匹配的规则会生效。 matcher始终匹配上游库表名,而不是路由后的目标库表名。- Changefeed 配置项
case-sensitive只影响表路由的matcher是否大小写敏感,不会改写{schema}和{table}展开结果的大小写。详情参见case-sensitive。
占位符
你可以在 target-schema 和 target-table 中使用以下占位符:
target-schema 和 target-table 的值只能包含字面文本、{schema} 和 {table}。如果使用 {db} 这类未知占位符,TiCDC 会拒绝该 Changefeed 配置,并返回 CDC:ErrInvalidTableRoutingRule 错误。
以源表 sales.orders 为例:
示例
路由一个库中的所有表
以下配置将 sales 库中的所有表路由到 archive 库,并在目标表名后追加 _bak:
[filter]
rules = ["sales.*"]
[sink]
[[sink.dispatchers]]
matcher = ["sales.*"]
target-schema = "archive"
target-table = "{table}_bak"
路由结果示例如下:
sales.orders会路由到archive.orders_bak。sales.order_items会路由到archive.order_items_bak。
将多个库路由到同一个目标库
将多个库路由到同一个目标库时,建议在 target-table 中包含 {schema},以确保目标表名唯一。
[filter]
rules = ["sales.*", "crm.*", "finance.*"]
[sink]
[[sink.dispatchers]]
matcher = ["sales.*", "crm.*", "finance.*"]
target-schema = "archive"
target-table = "{schema}_{table}"
路由结果示例如下:
sales.orders会路由到archive.sales_orders。crm.orders会路由到archive.crm_orders。finance.orders会路由到archive.finance_orders。
同时使用表路由和 Kafka Sink Topic、Partition 分发器
同一条 dispatcher 规则可以同时包含表路由字段和已有的分发字段:
[filter]
rules = ["sales.orders"]
[sink]
[[sink.dispatchers]]
matcher = ["sales.orders"]
topic = "order-events"
partition = "index-value"
target-schema = "public"
target-table = "orders"
在以上示例中,表路由将下游数据中暴露的库表名改为 public.orders。
表路由不会改变 Topic 或 Partition 的分发结果,topic 和 partition 分发器仍然按照上游表 sales.orders 进行匹配和分发计算。
输出行为
DDL 行为
启用表路由后,TiCDC 会改写 DDL 语句,使结构化 DDL 元数据和 SQL 文本中的库表名保持一致。
例如,如果配置以下规则:
[[sink.dispatchers]]
matcher = ["sales.*"]
target-schema = "archive"
target-table = "{table}_routed"
TiCDC 会将以下上游 DDL:
RENAME TABLE `sales`.`temp_table` TO `sales`.`renamed_table`;
改写为以下下游 DDL:
RENAME TABLE `archive`.`temp_table_routed` TO `archive`.`renamed_table_routed`;
如果 DDL 语句中包含表引用,且这些表引用匹配表路由规则,TiCDC 也会改写被引用的表名。例如,CREATE VIEW 语句中的表引用,以及 ALTER TABLE 语句中的外键引用都可以被改写。
对于 CREATE DATABASE、DROP DATABASE 和 ALTER DATABASE ... CHARACTER SET/COLLATE 这类库级 DDL,如果库名匹配表路由规则,TiCDC 会改写库名。如果同一个上游库匹配多条表路由规则,且这些规则解析出的目标库名不同,TiCDC 无法为该库级 DDL 确定唯一目标库,Changefeed 会返回表路由错误。
创建或更新 Changefeed 时,TiCDC 会基于当前同步范围内的表检查目标表冲突。运行期间,TiCDC 会在同步 CREATE TABLE、RENAME TABLE、DROP TABLE、DROP DATABASE 等 DDL 时更新冲突检测状态。库级 DDL 是否能确定唯一目标库,会在同步对应 DDL 时判断。
路由冲突检测
当两张不同的上游表在同一个 Changefeed 内被路由到同一个下游 (schema, table) 时,会发生路由冲突。TiCDC 不支持将多张上游表合并到同一张下游表。
例如,以下配置可能导致冲突:
[filter]
rules = ["sales.*", "crm.*"]
[sink]
[[sink.dispatchers]]
matcher = ["sales.*"]
target-schema = "archive"
target-table = "{table}"
[[sink.dispatchers]]
matcher = ["crm.*"]
target-schema = "archive"
target-table = "{table}"
如果 sales.orders 和 crm.orders 都在同步范围内,这两张表都会被路由到 archive.orders。TiCDC 会拒绝创建或更新 Changefeed,并返回 CDC:ErrTableRouteConflict 错误。
Changefeed 运行期间,如果 CREATE TABLE 或 RENAME TABLE 等 DDL 导致两张在当前同步范围内的上游表被路由到同一张目标表,Changefeed 会失败并返回 CDC:ErrTableRouteConflict 错误。
如果上游表被删除或重命名,TiCDC 会解除该上游表与目标表之间的路由关系。之后,新的上游表可以继续使用该目标表,但在同一时刻同一个目标表只能对应一张正在被当前 Changefeed 同步的上游表。