【TiDB 社区升级互助材料】TiCDC 最佳实践&上线前准备& FAQ

本文档由 2024年 TiDB 社区互助升级导师共建

什么是 TiCDC

TiCDC 是一款 TiDB 增量数据同步工具,通过拉取上游 TiKV 的数据变更日志,TiCDC 可以将数据解析为有序的行级变更数据输出到下游。

TiCDC 的版本需要和 TiDB 版本保持一致。TiCDC 支持从 4.x 的版本同步到 7.x 的版本,相关兼容性可见:TiCDC 兼容性

TiCDC 适用场景

TiCDC 适用于以下场景:

  • 提供多 TiDB 集群,跨区域数据高可用和容灾方案,保证在灾难发生时保证主备集群数据的最终一致性。

  • 提供同步实时变更数据到异构系统的服务,为监控、缓存、全文索引、数据分析、异构数据库使用等场景提供数据源。

TiCDC 主要特性

核心能力

TiCDC 提供了以下核心能力:

  • 提供 TiDB → TiDB 之间数据容灾复制的能力,实现秒级别 RPO 和分钟级别 RTO

  • 提供 TiDB 之间双向复制的能力,支持通过 TiCDC 构建多写多活的 TiDB 集群

  • 提供 TiDB → MySQL(或其他兼容 MySQL 协议的数据库)的低延迟的增量数据同步能力

  • 提供 TiDB → Kafka 增量数据同步能力,推荐的数据格式包含 Canal-JSONAvro

  • 提供 TiDB → 存储服务(如:Amazon S3、GCS、Azure Blob Storage 和 NFS)增量数据同步能力。

  • 提供表级别数据同步能力,支持同步过程中过滤数据库、表、DML、DDL 的能力

  • 高可用架构,无单点故障;支持动态添加、删除 TiCDC 节点

  • 支持通过 Open API 进行集群管理,包括查询任务状态;动态修改任务配置;动态创建、删除任务等

TiCDC 对于用户的价值和意义?

  1. 实时数据同步:TiCDC 能够实时捕获 TiDB 中的数据变更,并将这些变更同步到其他数据库、数据仓库或消息队列中,这对于需要实时数据的业务场景非常有用。

  2. 数据复制和备份:TiCDC 可以用于创建数据的实时复制或备份,这对于数据安全和灾难恢复至关重要。

  3. 异构数据库支持:通过 TiCDC,用户可以将数据同步到不同的数据库系统中,比如 MySQL、PostgreSQL、MongoDB 等,这有助于构建异构数据库环境。

  4. 微服务架构:在微服务架构中,TiCDC 可以帮助实现服务之间的数据解耦,每个服务可以独立地处理和响应数据变更。

  5. 数据湖构建:TiCDC 可以用于将数据实时同步到数据湖,支持复杂的数据分析和机器学习应用。

  6. 业务连续性:TiCDC 支持构建多活架构,提高业务的连续性和系统的可用性。

  7. 数据审计和合规性:TiCDC 可以记录数据的变更历史,帮助企业满足数据审计和合规性要求。

  8. 减少业务中断:TiCDC 可以在不中断业务的情况下同步数据,这对于需要 24/7 运行的系统尤其重要。

  9. 简化数据流处理:TiCDC 提供了一种简单的方式来构建数据流处理系统,因为它可以直接将数据变更作为流提供给下游系统。

  10. 降低成本:通过减少数据同步的复杂性和时间,TiCDC 可以帮助企业降低运维成本。

  11. 提高系统灵活性:TiCDC 允许用户根据业务需求灵活地选择同步的数据类型和目标系统。

  12. 支持云原生架构:TiCDC 与云原生架构兼容,可以在 Kubernetes 等环境中运行,提高系统的可扩展性和弹性。

  13. 易于使用和维护:TiCDC 提供了易于理解和使用的界面,使得配置和管理数据同步变得简单。

  14. 持续创新:TiDB 社区持续对 TiCDC 进行创新和改进,确保它能够满足不断变化的业务和技术需求。

TiCDC 架构

TiCDC 作为 TiDB 的增量数据同步工具,通过 PD 内部的 etcd 实现高可用,通过多个 TiCDC 进程获取 TiKV 节点上的数据改变,在内部进行排序、合并等处理之后,通过多个同步任务 (Changefeed),同时向多个下游系统进行数据同步。

在以上架构图中:

  • TiKV Server:代表 TiDB 集群中的 TiKV 节点,当数据发生改变时 TiKV 节点会主动将发生的数据改变以变更日志(KV change logs,简称 change logs)的方式发送给 TiCDC 节点。当然,当 TiCDC 节点发现收到的 change logs 并不是连续的,也会主动发起请求,获得需要的 change logs。

  • TiCDC:代表运行了运行 TiCDC 进程的各个节点。每个节点都运行一个 TiCDC 进程,每个进程会从 TiKV 节点中拉取一个或者多个表中的数据改变,并通过 Sink 模块同步到下游系统。

  • PD:代表 TiDB 集群中的调度模块,负责集群数据的事实调度,这个模块通常是由 3 个 PD 节点构成的,内部通过 etcd 集群来实现选举等高可用相关的能力。 TiCDC 集群使用了 PD 集群内置的 etcd 集群来保存自己的元数据信息,例如:节点的状态信息,changefeed 配置信息等。

另外,从上面的架构图中也可以看到,目前 TiCDC 支持将数据同步到 TiDB、MySQL 数据库、Kafka 以及存储服务等。

最佳实践

  • 使用 TiCDC 在两个 TiDB 集群间同步数据时,如果上下游的延迟超过 100 ms:

    • 对于 v6.5.2 之前的版本,推荐将 TiCDC 部署在下游 TiDB 集群所在的区域 (IDC, region)

    • 经过优化后,对于 v6.5.2 及之后的版本,推荐将 TiCDC 部署在上游集群所在的区域 (IDC, region)。

  • TiCDC 同步的表需要至少存在一个有效索引的表,有效索引的定义如下:

    • 主键 (PRIMARY KEY) 为有效索引。

    • 唯一索引 (UNIQUE INDEX) 中每一列在表结构中明确定义非空 (NOT NULL) 且不存在虚拟生成列 (VIRTUAL GENERATED COLUMNS)。

  • 在使用 TiCDC 实现容灾的场景下,为实现最终一致性,需要配置 redo log 并确保 redo log 写入的存储系统在上游发生灾难时可以正常读取。

什么情况下需要上 TiCDC?

TiCDC(TiDB Change Data Capture)是 TiDB 数据库的一个组件,它主要用于捕获和同步 TiDB 中的数据变更。在以下情况下,您可能需要使用 TiCDC:

  1. 数据同步:当您需要将 TiDB 中的数据同步到另一个数据库或数据仓库时,可以使用 TiCDC 来实现增量数据同步。

  2. 数据迁移:在进行数据迁移时,TiCDC 可以帮助您将数据从一个 TiDB 集群迁移到另一个集群。

  3. 数据备份:TiCDC 可以用于创建数据的实时备份,这对于数据恢复和灾难恢复非常重要。

  4. 多活架构:在构建多活(multi-active)架构时,TiCDC 可以用来在不同的数据中心之间同步数据,以确保数据的一致性。

  5. 实时分析:如果您需要对数据进行实时分析,TiCDC 可以将变更的数据实时同步到适合分析的系统中,比如 Elasticsearch 或 Apache Flink。

  6. 业务解耦:在微服务架构中,TiCDC 可以帮助将业务逻辑与数据存储解耦,让不同的服务可以独立地处理数据变更。

  7. 审计和合规性:TiCDC 可以用于记录数据的变更历史,以满足审计和合规性要求。

  8. 数据订阅和流处理:TiCDC 提供了数据流,可以被用于构建数据订阅服务或与流处理系统集成。

  9. 数据湖构建:构建数据湖时,TiCDC 可以将操作型数据实时同步到数据湖中,以便于后续的数据分析和机器学习任务。

TiCDC 上线前准备

TiCDC 安装部署与集群运维

本文档介绍部署 TiCDC 集群的软硬件环境要求,如何安装部署 TiCDC 集群,以及如何对 TiCDC 集群进行运维操作。你可以选择在安装 TiDB 集群的同时部署 TiCDC,也可以对原有 TiDB 集群新增 TiCDC 组件。

软件和硬件环境推荐配置

在生产环境中,TiCDC 的软件和硬件配置推荐如下:

td {white-space:nowrap;border:1px solid #dee0e3;font-size:10pt;font-style:normal;font-weight:normal;vertical-align:middle;word-break:normal;word-wrap:normal;}
Linux 操作系统 版本
Red Hat Enterprise Linux 7.3 及以上
CentOS 7.3 及以上
CPU 内存 硬盘 网络 TiCDC 集群实例数量(生产环境最低要求)
16 核+ 64 GB+ 500 GB+ SSD 类型硬盘 万兆网卡(2 块最佳) 2

更多信息参见 TiDB 软件和硬件环境建议配置

在安装之前,请确认 TiUP 中控机与 TiCDC 目标主机的 SSH 互信及 sudo 免密已经完成配置。

使用 TiUP 在原有 TiDB 集群上移除或缩容 TiCDC 组件

推荐使用 TiUP 完成对 TiCDC 集群节点的缩容。使用类似下面的命令完成缩容:

tiup cluster scale-in <cluster-name> --node 10.0.1.4:8300

更多用例说明,请参考缩容 TiCDC 节点

使用 TiUP 升级 TiCDC 集群

TiUP 支持升级 TiDB 集群,包括 TiCDC 组件。执行升级指令时,TiUP 会自动升级 TiCDC 组件,无需额外操作。操作示例如下:

tiup update --self && \
tiup update --all && \
tiup cluster upgrade <cluster-name> <version> --transfer-timeout 600

注意

命令中的 <cluster-name> 需要替换为集群名字,<version> 需要替换为目标版本号,例如 v7.5.1。

升级的注意事项

升级 TiCDC 集群时,需要注意以下事项:

  • TiCDC v4.0.2 对 changefeed 的配置做了调整,请参阅配置文件兼容注意事项

  • 升级期间遇到的问题及其解决办法,请参阅使用 TiUP 升级 TiDB

  • TiCDC 自 v6.3.0 起支持滚动升级,使用 TiUP 升级 TiCDC 节点期间,能够保证同步延迟稳定,不发生剧烈波动。满足以下条件将自动启用滚动升级:

    • TiCDC 版本大于等于 v6.3.0。

    • TiUP 版本大于等于 v1.11.3。

    • 集群中至少有两个正在运行的 TiCDC 实例。

使用 TiUP 变更 TiCDC 集群配置

本节介绍如何使用 TiUP 的 tiup cluster edit-config 命令来修改 TiCDC 的配置。在以下例子中,假设需要把 TiCDC 的 gc-ttl 从默认值 86400 修改为 172800,即 48 小时。

  1. 执行 tiup cluster edit-config 命令,注意将 <cluster-name> 替换成实际的集群名:
tiup cluster edit-config <cluster-name>
  1. 在 vi 编辑器页面,修改 server-configs 下的 cdc 配置:
server_configs:
  tidb: {}
  tikv: {}
  pd: {}
  tiflash: {}
  tiflash-learner: {}
  pump: {}
  drainer: {}
  cdc:
    gc-ttl: 172800
  1. 以上把 TiCDC 的 gc-ttl 的值设置为 48 小时。

  2. 执行 tiup cluster reload -R cdc 命令重新加载配置。

使用 TiUP 终止和启动 TiCDC 节点

使用 TiUP 可以方便地终止和启动 TiCDC 节点,命令如下:

  • 终止 TiCDC 节点:tiup cluster stop -R cdc

  • 启动 TiCDC 节点:tiup cluster start -R cdc

  • 重启 TiCDC 节点:tiup cluster restart -R cdc

使用加密传输 (TLS) 功能

请参阅为 TiDB 组件间通信开启加密传输

使用 TiCDC 命令行工具来查看集群状态

执行以下命令来查看 TiCDC 集群运行状态,注意需要将 v<CLUSTER_VERSION> 替换为 TiCDC 集群版本,例如 v7.5.1

tiup cdc:v<CLUSTER_VERSION> cli capture list --server=http://10.0.10.25:8300
[
  {"id": "806e3a1b-0e31-477f-9dd6-f3f2c570abdd","is-owner": true,"address": "127.0.0.1:8300","cluster-id": "default"
  },
  {"id": "ea2a4203-56fe-43a6-b442-7b295f458ebc","is-owner": false,"address": "127.0.0.1:8301","cluster-id": "default"
  }
]
  • id:表示服务进程的 ID。

  • is-owner:表示该服务进程是否为 owner 节点。

  • address:该服务进程对外提供接口的地址。

  • cluster-id:该 TiCDC 的集群 ID,默认值为 default

TiDB社区用户 TiCDC 实践文章:

专栏 - TiDB TiCDC使用实践 | TiDB 社区

专栏 - 基于 TiCDC 创建灾备和容灾切换 | TiDB 社区

专栏 - TiCDC系列分享-02-剖析同步模型与基本架构 | TiDB 社区

专栏 - TiCDC 6.0 原理之 Sorter 演进 | TiDB 社区

专栏 - TiCDC+Confluent同步数据到Oracle | TiDB 社区

专栏 - TiCDC系列分享 Open API与业务系统集成 | TiDB 社区

专栏 - TiCDC系列分享-01-简述产生背景及使用概况 | TiDB 社区

专栏 - 一场由TiCDC异常引发的GC不干活导致的Tikv硬盘使用问题 | TiDB 社区

专栏 - TiCDC 应用场景解析 | TiDB 社区

专栏 - 10倍提升-TiCDC性能调优实践 | TiDB 社区

专栏 - TiDB 数据库大版本升级-基于TiCDC异机升级 | TiDB 社区

专栏 - TiCDC 源码解读(1)-- TiCDC 的架构概览 | TiDB 社区

专栏 - TiCDC 在多种场景的新特性的应用 | TiDB 社区

专栏 - TiDB 之 TiCDC6.0 初体验 | TiDB 社区

专栏 - 初识TiDB的增量数据同步工具TiCDC | TiDB 社区

专栏 - TiCDC核心原理解析 | TiDB 社区

专栏 - 基于 TiCDC 的 TiDB 复制集群的计划内和计划外切换验证步骤 | TiDB 社区

专栏 - TiCDC 源码解读(3)-- TiCDC 集群工作过程解析 | TiDB 社区

专栏 - TiCDC 源码解读(2)-- TiKV CDC 模块介绍 | TiDB 社区

专栏 - TiCDC 实践:TiDB 集群合并 | TiDB 社区

专栏 - 基于TiCDC同步的主从集群数据校验 | TiDB 社区

专栏 - TiCDC同步延迟问题处理 | TiDB 社区

专栏 - 体验TiDB v6.0.0 之TiCDC | TiDB 社区

专栏 - TiDB v5.1.2 - TiCDC 不同步,checkpointTs 不推进的问题排查 | TiDB 社区

专栏 - Flink 最佳实践之 通过 TiCDC 将 TiDB 数据流入 Flink | TiDB 社

专栏 - TiDB实例间数据同步之TiCDC实践 | TiDB 社区

专栏 - 【资源汇总】TiDB-TiCDC 源码解读系列最全资源!!! | TiDB 社区

专栏 - TiCDC 源码阅读(七) TiCDC Sorter 模块揭秘 | TiDB 社区

专栏 - TiCDC 源码阅读(六)TiCDC Puller 模块介绍 | TiDB 社区

专栏 - TiCDC 源码阅读(五)TiCDC 对 DDL 的处理和 Filter 解析 | TiDB 社区

专栏 - TiCDC 源码解读(6)- TiCDC Puller 模块介绍 | TiDB 社区

专栏 - TiCDC 源码解读(5)-- TiCDC DDL 事件处理逻辑 与 Filter 实现介绍 | TiDB 社区

专栏 - TiCDC 源码解读(4)-- TiCDC Scheduler 工作原理解析 | TiDB 社区

专栏 - TiCDC迁移-TiDB到MySQL测试 | TiDB 社区

专栏 - TiCDC canal_json的实际应用 | TiDB 社区

专栏 - ticdc没报错,tso却不变的奇怪现象 | TiDB 社区

专栏 - 基于TiCDC 实现的双云架构实践 | TiDB 社区

专栏 - 使用 TiCDC 实时同步 TiDB 数据到备用逃生环境的实践 | TiDB 社区

专栏 - TiCDC使用心得 | TiDB 社区

TiCDC 常见问题解答

本文档总结了使用 TiCDC 时经常遇到的问题。

注意:本文档 cdc cli 命令中指定 server 地址为 --server= http://127.0.0.1:8300,在使用时你需要根据实际地址进行替换。

TiCDC 创建任务时如何选择 start-ts?

首先需要理解同步任务的 start-ts 对应于上游 TiDB 集群的一个 TSO,同步任务会从这个 TSO 开始请求数据。所以同步任务的 start-ts 需要满足以下两个条件:

  • start-ts 的值需要大于 TiDB 集群当前的 tikv_gc_safe_point,否则创建任务时会报错。

  • 启动任务时,需要保证下游已经具有 start-ts 之前的所有数据。对于同步到消息队列等场景,如果不需要保证上下游数据的一致,可根据业务场景放宽此要求。

如果不指定 start-ts 或者指定 start-ts=0,在启动任务的时候会去 PD 获取一个当前 TSO,并从该 TSO 开始同步。

为什么 TiCDC 创建任务时提示部分表不能同步?

在使用 cdc cli changefeed create 创建同步任务时会检查上游表是否符合同步要求。如果存在表不满足同步限制,会提示 some tables are not eligible to replicate 并列出这些不满足的表。如果选择 Yy 则会继续创建同步任务,并且同步过程中自动忽略这些表的所有更新。如果选择其他输入,则不会创建同步任务。

如何查看 TiCDC 同步任务的状态?

可以使用 cdc cli 查询同步任务的状态。例如:

cdc cli changefeed list --server=http://127.0.0.1:8300

上述命令输出如下:

[{"id": "4e24dde6-53c1-40b6-badf-63620e4940dc","summary": {"state": "normal","tso": 417886179132964865,"checkpoint": "2020-07-07 16:07:44.881","error": null}}]
  • checkpoint:即为 TiCDC 已经将该时间点前的数据同步到了下游。

  • state 为该同步任务的状态,状态的值和含义参考 TiCDC 同步任务状态

注意:该功能在 TiCDC 4.0.3 版本引入。

TiCDC 的 gc-ttl 是什么?

从 TiDB v4.0.0-rc.1 版本起,PD 支持外部服务设置服务级别 GC safepoint。任何一个服务可以注册更新自己服务的 GC safepoint。PD 会保证任何晚于该 GC safepoint 的 KV 数据不会在 TiKV 中被 GC 清理掉。

在 TiCDC 中启用了这一功能,用来保证 TiCDC 在不可用、或同步任务中断情况下,可以在 TiKV 内保留 TiCDC 需要消费的数据不被 GC 清理掉。

启动 TiCDC server 时可以通过 gc-ttl 指定 GC safepoint 的 TTL,也可以通过 TiUP 修改 TiCDC 的 gc-ttl,默认值为 24 小时。在 TiCDC 中这个值有如下两重含义:

  • 当 TiCDC 服务全部停止后,由 TiCDC 在 PD 所设置的 GC safepoint 保存的最长时间。

  • 当 TiCDC 的 GC safepoint 阻塞 TiKV GC 数据时,gc-ttl 表示 TiCDC 同步任务的最大同步延迟,若同步任务延迟超过 gc-ttl 所设置的值,那么该同步任务就会进入 failed 状态,并报 ErrGCTTLExceeded 错误,无法被恢复,不再阻塞 GC safepoint 推进。

以上第二种行为是在 TiCDC v4.0.13 版本及之后版本中新增的。目的是为了防止 TiCDC 中某个同步任务停滞时间过长,导致上游 TiKV 集群的 GC safepoint 长时间不推进,保留的旧数据版本过多,进而影响上游集群性能。

注意:在某些应用场景中,比如使用 Dumpling/BR 全量同步后使用 TiCDC 接增量同步时,默认的 gc-ttl 为 24 小时可能无法满足需求。此时应该根据实际情况,在启动 TiCDC server 时指定 gc-ttl 的值。

TiCDC GC safepoint 的完整行为是什么?

TiCDC 服务启动后,如果有任务开始同步,TiCDC owner 会根据所有同步任务最小的 checkpoint-ts 更新到 PD service GC safepoint,service GC safepoint 可以保证该时间点及之后的数据不被 GC 清理掉。如果 TiCDC 中某个同步任务中断、或者被用户主动停止,则该任务的 checkpoint-ts 不会再改变,PD 对应的 service GC safepoint 最终会停滞在该任务的 checkpoint-ts 处不再更新。

如果该同步任务停滞的时间超过了 gc-ttl 指定的时长,那么该同步任务就会进入 failed 状态,并且无法被恢复,PD 对应的 service GC safepoint 就会继续推进。

TiCDC 为 service GC safepoint 设置的默认存活有效期为 24 小时,即 TiCDC 服务中断 24 小时内恢复能保证 TiCDC 继续同步所需的数据不因 GC 而丢失。

Failed 同步任务失败后如何恢复?

  1. 通过 cdc cli changefeed query 查询同步任务的错误信息,尽快修复错误。

  2. 调大 gc-ttl 的值,给修复错误留出时间,确保错误修复后不会因为同步延迟超过 gc-ttl 而导致同步任务进入 failed 状态。

  3. 在评估系统影响后,调大 TiDB 的 tidb_gc_life_time 的值以阻止 GC、保留数据,确保错误修复后不会因为 GC 清理数据而导致同步任务进入 failed 状态。

如何理解 TiCDC 时区和上下游数据库系统时区之间的关系?

上游时区 TiCDC 时区 下游时区
配置方式 时区支持 启动 ticdc server 时的 --tz 参数 sink-uri 中的 time-zone 参数
说明 上游 TiDB 的时区,影响 timestamp 类型的 DML 操作和与 timestamp 类型列相关的 DDL 操作。 TiCDC 会将假设上游 TiDB 的时区和 TiCDC 时区配置相同,对 timestamp 类型的列进行相关处理。 下游 MySQL 将按照下游的时区设置对 DML 和 DDL 操作中包含的 timestamp 进行处理。

注意

请谨慎设置 TiCDC server 的时区,因为该时区会用于时间类型的转换。上游时区、TiCDC 时区和下游时区应该保持一致。TiCDC server 时区使用的优先级如下:

  • 最优先使用 --tz 传入的时区。

  • 没有 --tz 参数,会尝试读取 TZ 环境变量设置的时区。

  • 如果还没有 TZ 环境变量,会从 TiCDC server 运行机器的默认时区。

创建同步任务时,如果不指定 --config 配置文件,TiCDC 的默认的行为是什么?

在使用 cdc cli changefeed create 命令时如果不指定 --config 参数,TiCDC 会按照以下默认行为创建同步任务:

  • 同步所有的非系统表

  • 只同步包含有效索引的表

TiCDC 是否支持输出 Canal 协议的变更数据?

支持。注意:对于 Canal 协议,TiCDC 只支持 JSON 输出格式,对 protobuf 格式尚未提供官方支持。要开启 Canal 协议的输出,只需在 --sink-uri 配置中指定 protocolcanal-json 即可。例如:

cdc cli changefeed create --server=http://127.0.0.1:8300 --sink-uri="kafka://127.0.0.1:9092/cdc-test?kafka-version=2.4.0&protocol=canal-json" --config changefeed.toml

注意

  • 该功能在 TiCDC 4.0.2 版本引入。

  • 目前 TiCDC 仅支持将 Canal-JSON 格式的变更数据输出到 MQ 类的 Sink(例如 Kafka)。

更多信息请参考 TiCDC Changefeed 配置参数

为什么 TiCDC 到 Kafka 的同步任务延时越来越大?

  • 请参考如何查看 TiCDC 同步任务的状态?检查下同步任务的状态是否正常。

  • 请适当调整 Kafka 的以下参数:

    • message.max.bytes,将 Kafka 的 server.properties 中该参数调大到 1073741824 (1 GB)。

    • replica.fetch.max.bytes,将 Kafka 的 server.properties 中该参数调大到 1073741824 (1 GB)。

    • fetch.message.max.bytes,适当调大 consumer.properties 中该参数,确保大于 message.max.bytes

TiCDC 把数据同步到 Kafka 时,能在 TiDB 中控制单条消息大小的上限吗?

对于 Avro 和 Canal-JSON 格式,消息是以行变更为单位发送的,一条 Kafka Message 仅包含一条行变更。一般情况下,消息的大小不会超过 Kafka 单条消息上限,因此,一般不需要限制单条消息大小。如果单条 Kafka 消息大小确实超过 Kafka 上限,请参考为什么 TiCDC 到 Kafka 的同步任务延时越来越大

对于 Open Protocol 格式,一条 Kafka Message 可能包含多条行变更。因此,有可能存在某条 Kafka Message 消息过大。可以通过 max-message-bytes 控制每次向 Kafka broker 发送消息的最大数据量(可选,默认值 10 MB),通过 max-batch-size 参数指定每条 kafka 消息中变更记录的最大数量(可选,默认值 16)。

在一个事务中对一行进行多次修改,TiCDC 会输出多条行变更事件吗?

不会,在进行事务操作时,对于在一个事务内多次修改同一行的情况,TiDB 仅会将最新一次的修改结果发送给 TiKV。因此 TiCDC 仅能获取到最新一次修改的结果。

TiCDC 把数据同步到 Kafka 时,一条消息中会不会包含多种数据变更?

会,一条消息中可能出现多个 updatedeleteupdatedelete 也有可能同时存在。

TiCDC 把数据同步到 Kafka 时,如何查看 TiCDC Open protocol 输出变更数据中的时间戳、表名和库名?

这些信息包含在 Kafka 消息的 Key 中,比如:

{"ts":<TS>,"scm":<Schema Name>,"tbl":<Table Name>,"t":1}

更多信息请参考 Open protocol Event 格式定义

TiCDC 把数据同步到 Kafka 时,如何确定一条消息中包含的数据变更发生在哪个时间点?

把 Kafka 消息的 Key 中的 ts 右移 18 位即得 unix timestamp。

TiCDC Open protocol 如何标示 null 值?

Open protocol 的输出中 type = 6 即为 null,比如:

类型 Code 输出示例 说明
Null 6 {“t”:6,“v”:null}

更多信息请参考 Open protocol Event 格式定义

如何区分 TiCDC Open Protocol 中的 Row Changed Event 是 INSERT 事件还是 UPDATE 事件?

  • 如果同时存在 "p""u" 字段为 UPDATE 事件

  • 如果只存在 "u" 字段则为 INSERT 事件

  • 如果只存在 "d" 字段则为 DELETE 事件

更多信息请参考 Open protocol Row Changed Event 格式定义

TiCDC 占用多少 PD 的存储空间

TiCDC 使用 PD 内部的 etcd 来存储元数据并定期更新。因为 etcd 的多版本并发控制 (MVCC) 以及 PD 默认的 compaction 间隔是 1 小时,TiCDC 占用的 PD 存储空间与 1 小时内元数据的版本数量成正比。在 v4.0.5、v4.0.6、v4.0.7 三个版本中 TiCDC 存在元数据写入频繁的问题,如果 1 小时内有 1000 张表创建或调度,就会用尽 etcd 的存储空间,出现 etcdserver: mvcc: database space exceeded 错误。出现这种错误后需要清理 etcd 存储空间,参考 etcd maintenance space-quota。如果你的 TiCDC 版本为 v4.0.5、v4.0.6 或 v4.0.7,建议升级到 v4.0.9 及以后版本。

TiCDC 支持同步大事务吗?有什么风险吗?

TiCDC 对大事务(大小超过 5 GB)提供部分支持,根据场景不同可能存在以下风险:

  • 可能导致主从同步延迟大幅增高。

  • 当 TiCDC 内部处理能力不足时,可能出现同步任务报错 ErrBufferReachLimit

  • 当 TiCDC 内部处理能力不足或 TiCDC 下游吞吐能力不足时,可能出现内存溢出 (OOM)。

从 v6.2 版本开始,TiCDC 支持拆分单表事务功能,可大幅降低同步大事务的延时和内存消耗。因此,在业务对事务原子性要求不高的场景下,建议通过设置 sink uri 参数 transaction-atomicity 打开拆分事务功能以解决可能出现的同步延迟和 OOM 问题。

如果实际同步过程中仍然遇到了上述错误,建议将包含大事务部分的增量数据通过 BR 进行增量恢复,具体操作如下:

  1. 记录因为大事务而终止的 changefeed 的 checkpoint-ts,将这个 TSO 作为 BR 增量备份的 --lastbackupts,并执行增量备份

  2. 增量备份结束后,可以在 BR 日志输出中找到类似 ["Full backup Failed summary : total backup ranges: 0, total success: 0, total failed: 0"] [BackupTS=421758868510212097] 的日志,记录其中的 BackupTS

  3. 执行增量恢复

  4. 建立一个新的 changefeed,从 BackupTS 开始同步任务。

  5. 删除旧的 changefeed。

TiCDC 是否会将有损 DDL 产生的数据变更同步到下游?

有损 DDL 是指在 TiDB 中执行可能会导致数据改变的 DDL。一些常见的有损 DDL 操作包括:

  • 修改列的类型,例如:INT → VARCHAR

  • 修改列的长度,例如:VARCHAR(20) → VARCHAR(10)

  • 修改列的精度,例如:DECIMAL(10, 3) → DECIMAL(10, 2)

  • 修改列的符号(有符号数/无符号数),例如:INT UNSIGNED → INT SIGNED

在 TiDB v7.1.0 之前,TiCDC 会将一条新旧数据相同的 DML 事件同步到下游。当下游是 MySQL 时,这些 DML 事件不会产生任何数据变更,只有下游接收并执行该 DDL 语句后,数据才会发生变更。但是当下游是 Kafka 或者云存储时,TiCDC 会写入一条无用的数据到下游。

从 TiDB v7.1.0 开始,TiCDC 会过滤掉这些无用的 DML 事件,不再将它们同步到下游。

同步 DDL 到下游 MySQL 5.7 时为什么时间类型字段默认值不一致?

比如上游 TiDB 的建表语句为 create table test (id int primary key, ts timestamp),TiCDC 同步该语句到下游 MySQL 5.7,MySQL 使用默认配置,同步得到的表结构如下所示,timestamp 字段默认值会变成 CURRENT_TIMESTAMP

mysql root@127.0.0.1:test show create table test;
+-------+----------------------------------------------------------------------------------+| Table | Create Table                                                                     |+-------+----------------------------------------------------------------------------------+| test  | CREATE TABLE test

( || |

id

int(11) NOT NULL, || |

ts

timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, || | PRIMARY KEY (

id

) || | ) ENGINE=InnoDB DEFAULT CHARSET=latin1 |±------±---------------------------------------------------------------------------------+1 row in set

产生表结构不一致的原因是 explicit_defaults_for_timestamp默认值在 TiDB 和 MySQL 5.7 不同。从 TiCDC v5.0.1/v4.0.13 版本开始,同步到 MySQL 会自动设置 session 变量 explicit_defaults_for_timestamp = ON,保证同步时间类型时上下游行为一致。对于 v5.0.1/v4.0.13 以前的版本,同步时间类型时需要注意 explicit_defaults_for_timestamp 默认值不同带来的兼容性问题。

使用 TiCDC 创建同步任务时将 safe-mode 设置为 true 后,为什么上游的 INSERT/UPDATE 语句经 TiCDC 同步到下游后变为了 REPLACE INTO

TiCDC 提供至少一次的数据同步保证,当下游有重复数据时,会引起写冲突。为了避免该问题,TiCDC 会将 INSERTUPDATE 语句转成 REPLACE INTO 语句。该行为由 safe-mode 参数来控制。

在 v6.1.3 版本之前,safe-mode 默认为 true,即所有的 INSERTUPDATE 语句都转成 REPLACE INTO 语句。在 v6.1.3 及之后版本,系统能自动判断下游是否存在重复数据,safe-mode 默认更改为 false,当系统判断下游无重复数据时,会直接同步 INSERTUPDATE 语句。

数据同步下游的 Sink 为 TiDB 或 MySQL 时,下游数据库的用户需要哪些权限?

Sink 为 TiDB 或 MySQL 时,下游数据库的用户需要以下权限:

  • Select

  • Index

  • Insert

  • Update

  • Delete

  • Create

  • Drop

  • Alter

  • Create View

如果要同步 recover table 到下游 TiDB,需要有 Super 权限。

为什么 TiCDC 需要使用磁盘,什么时候会写磁盘,TiCDC 能否利用内存缓存提升同步性能?

TiCDC 需要磁盘是为了缓冲上游写入高峰时下游消费不及时堆积的数据。TiCDC 正常运行期间都需要写入磁盘,但这通常不是同步吞吐和同步延时的瓶颈,写磁盘对延时影响在百毫秒内。TiCDC 也利用了内存来提升加速读取磁盘中的数据,以提升同步性能。

为什么在上游使用了 TiDB Lightning 物理导入模式和 BR 恢复了数据之后,TiCDC 同步会出现卡顿甚至卡住?

目前 TiCDC 尚未完全适配 TiDB Lightning 物理导入模式 (Physical Import Mode) 和 BR,请避免在使用 TiCDC 同步的表上使用 TiDB Lightning 物理导入模式和 BR。否则,可能会出现未知的错误,例如 TiCDC 同步卡住、同步延迟大幅增加、或者同步数据丢失。

如果有某些使用 TiCDC 同步的表需要使用 TiDB Lightning 物理导入模式或者 BR 恢复数据,可以这么做:

  1. 删除涉及这些表的 TiCDC 同步任务。

  2. 使用 TiDB Lightning 物理导入模式或 BR 在 TiCDC 的上游集群和下游集群分别恢复数据。

  3. 恢复完成并检查了上下游集群对应表的数据一致性之后,使用上游备份的时间点 (TSO) 作为 TiCDC 同步任务的 start-ts,创建新的 TiCDC 同步任务,进行增量同步。例如,假设上游集群的 BR 备份的 snapshot 时间点为 431434047157698561,那么可以使用以下命令创建新的 TiCDC 同步任务:

cdc cli changefeed create -c "upstream-to-downstream-some-tables" --start-ts=431434047157698561 --sink-uri="mysql://root@127.0.0.1:4000? time-zone="

为什么恢复暂停的 changefeed 后,changefeed 同步延迟越来越高,数分钟后才恢复正常?

当 changefeed 启动时,为了补齐 changefeed 暂停期间产生的增量数据日志,TiCDC 需要扫描 TiKV 中数据的历史版本,待扫描完毕后,才能够继续推进复制过程,扫描过程可能长达数分钟到数十分钟。

在两个异地 TiDB 集群之间同步数据,如何部署 TiCDC?

对于 v6.5.2 之前的版本,建议将 TiCDC 部署在下游 TiDB 集群。这是因为,如果上下游网络延迟较大,例如超过 100 ms 时,由于 MySQL 传输协议的原因,TiCDC 向下游执行 SQL 的延迟会急剧增加,导致系统的吞吐下降。部署在下游能够极大缓解该问题。经过优化后,v6.5.2 及之后的版本建议将 TiCDC 部署在上游集群。

如何理解 DML 和 DDL 语句之间的执行顺序?

目前,TiCDC 采用了以下执行顺序:

  1. TiCDC 阻塞受 DDL 影响的表的同步进度,直到 DDL CommiTs 的时间点,以确保在 DDL CommiTs 之前执行的 DML 先成功同步到下游。

  2. TiCDC 继续同步 DDL。当存在多个 DDL 时,TiCDC 是以串行的方式进行同步的。

  3. 当 DDL 在下游执行完成之后,TiCDC 继续同步 DDL CommiTs 之后执行的 DML。

如何对比上下游数据的一致性?

如果下游是 TiDB 集群或者 MySQL,我们推荐使用 sync diff inspector 工具进行数据对比。

单表数据同步只能在一个 TiCDC 节点上运行,TiCDC 是否考虑使用多个节点同步多表数据?

从 v7.1.0 起,TiCDC 支持 MQ sink 按照 TiKV Region 粒度来同步数据变更日志,实现处理能力上的可扩展性,使得 TiCDC 能够同步 Region 数量庞大的单表。如需开启,请在 TiCDC 配置文件中配置以下参数:

[scheduler]enable-table-across-nodes = true

上游有运行时间比较长的未提交事务,TiCDC 同步是否会被卡住?

TiDB 有事务超时的机制,当事务运行超过 max-txn-ttl 后,会被 TiDB 强制回滚。TiCDC 遇到未提交的事务,会等待其提交后再继续同步其数据,因此会出现同步延迟。

为什么通过 TiDB Operator 部署的 TiCDC 集群无法使用 cdc cli 命令进行操作?

因为通过 TiDB Operator 部署的 TiCDC 集群的默认端口号为 8301, 而 cdc cli 命令默认连接的 cdc 服务器的端口号是 8300。在使用 cdc cli 操作 TiCDC 集群时,你需要显式地指定 --server 参数,如下:

./cdc cli changefeed list --server "127.0.0.1:8301"
[
  {"id": "4k-table","namespace": "default","summary": {"state": "stopped","tso": 441832628003799353,"checkpoint": "2023-05-30 22:41:57.910","error": null
    }
  },
  {"id": "big-table","namespace": "default","summary": {"state": "normal","tso": 441872834546892882,"checkpoint": "2023-06-01 17:18:13.700","error": null
    }
  }
]

TiCDC 故障处理

本文档总结了使用 TiCDC 过程中常见的运行故障及解决方案。

注意

本文档 cdc cli 命令中指定 TiCDC Server 地址为 --server= http://127.0.0.1:8300,在使用时需根据实际地址进行替换。

TiCDC 同步任务出现中断

如何判断 TiCDC 同步任务出现中断?

  • 通过 Grafana 检查同步任务的 changefeed checkpoint 监控项。注意选择正确的 changefeed id。如果该值不发生变化或者查看 checkpoint lag 是否不断增大,可能同步任务出现中断。

  • 通过 Grafana 检查 exit error count 监控项,该监控项大于 0 代表同步任务出现错误。

  • 通过 cdc cli changefeed listcdc cli changefeed query 命令查看同步任务的状态信息。任务状态为 stopped 代表同步中断,error 项会包含具体的错误信息。任务出错后可以在 TiCDC server 日志中搜索 error on running processor 查看错误堆栈,帮助进一步排查问题。

  • 部分极端异常情况下 TiCDC 出现服务重启,可以在 TiCDC server 日志中搜索 FATAL 级别的日志排查问题。

如何查看 TiCDC 同步任务是否被人为终止?

可以使用 cdc cli 查询同步任务是否被人为终止。例如:

cdc cli changefeed query --server=http://127.0.0.1:8300 --changefeed-id 28c43ffc-2316-4f4f-a70b-d1a7c59ba79f

上述命令的输出中 state 标志这个同步任务的状态,状态的值和含义参考 TiCDC 同步任务状态

如何处理 TiCDC 同步任务的中断?

目前已知可能发生的同步中断包括以下场景:

  • 下游持续异常,TiCDC 多次重试后仍然失败。

    • 该场景下 TiCDC 会保存任务信息,由于 TiCDC 已经在 PD 中设置的 service GC safepoint,在 gc-ttl 的有效期内,同步任务 checkpoint 之后的数据不会被 TiKV GC 清理掉。

    • 处理方法:在下游恢复正常后,通过 cdc cli changefeed resume 恢复同步任务。

  • 因下游存在不兼容的 SQL 语句,导致同步不能继续。

    • 该场景下 TiCDC 会保存任务信息,由于 TiCDC 已经在 PD 中设置的 service GC safepoint,在 gc-ttl 的有效期内,同步任务 checkpoint 之后的数据不会被 TiKV GC 清理掉。

    • 处理方法:

      • 先通过 cdc cli changefeed query 查询同步任务状态信息,记录 checkpoint-ts 值。

      • 使用新的任务配置文件,增加 ignore-txn-start-ts 参数跳过指定 start-ts 对应的事务。

      • 通过 cdc cli changefeed pause -c <changefeed-id> 暂停同步任务。

      • 通过 cdc cli changefeed update -c <changefeed-id> --config <config-file-path> 指定新的任务配置文件。

      • 通过 cdc cli changefeed resume -c <changefeed-id> 恢复同步任务。

同步任务中断,尝试再次启动后 TiCDC 发生 OOM,应该如何处理?

升级 TiDB 集群和 TiCDC 集群到最新版本。该 OOM 问题在 v4.0.14 及之后的 v4.0 版本,v5.0.2 及之后的 v5.0 版本,更新的版本上已得到缓解。

如何处理 TiCDC 创建同步任务或同步到 MySQL 时遇到 Error 1298: Unknown or incorrect time zone: 'UTC' 错误?

这是因为下游 MySQL 没有加载时区,可以通过 mysql_tzinfo_to_sql 命令加载时区,加载后就可以正常创建任务或同步任务。

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p

显示类似于下面的输出则表示导入已经成功:

Enter password:
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.

如果下游是特殊的 MySQL 环境(某种公有云 RDS 或某些 MySQL 衍生版本等),使用上述方式导入时区失败,则可以通过设置 time-zone 为空值来使用下游默认时区,例如:time-zone=""

在 TiCDC 中使用时区时,建议显式指定时区,例如:time-zone="Asia/Shanghai"。同时,请确保 TiCDC Server 的 tz 时区配置、Sink URI 中的 time-zone 时区配置和下游数据库的时区配置保持一致。这样可以避免因时区不一致导致的数据不一致问题。

如何处理升级 TiCDC 后配置文件不兼容的问题?

请参阅配置文件兼容注意事项

TiCDC 启动任务的 start-ts 时间戳与当前时间差距较大,任务执行过程中同步中断,出现错误 [CDC:ErrBufferReachLimit],怎么办?

自 v4.0.9 起可以尝试开启 unified sorter 特性进行同步;或者使用 BR 工具进行一次增量备份和恢复,然后从新的时间点开启 TiCDC 同步任务。TiCDC 将会在后续版本中对该问题进行优化。

当 changefeed 的下游为类 MySQL 数据库时,TiCDC 执行了一个耗时较长的 DDL 语句,阻塞了所有其他 changefeed,应该怎样处理?

  1. 首先暂停执行耗时较长的 DDL 的 changefeed。此时可以观察到,这个 changefeed 暂停后,其他的 changefeed 不再阻塞了。

  2. 在 TiCDC log 中搜寻 apply job 字段,确认耗时较长的 DDL 的 start-ts

  3. 手动在下游执行该 DDL 语句,执行完毕后进行下面的操作。

  4. 修改 changefeed 配置,将上述 start-ts 添加到 ignore-txn-start-ts 配置项中。

  5. 恢复被暂停的 changefeed。

使用 TiCDC 创建 changefeed 时报错 [tikv:9006]GC life time is shorter than transaction duration, transaction starts at xx, GC safe point is yy,该如何处理?

执行 pd-ctl service-gc-safepoint --pd <pd-addrs> 命令查询当前的 GC safepoint 与 service GC safepoint。如果 GC safepoint 小于 TiCDC changefeed 同步任务的开始时间戳 start-ts,可以直接在 cdc cli create changefeed 命令后加上 --disable-gc-check 参数创建 changefeed。

如果 pd-ctl service-gc-safepoint --pd <pd-addrs> 的结果中没有 gc_worker service_id

  • 如果 PD 的版本 <= v4.0.8,详见 PD issue #3128

  • 如果 PD 是由 v4.0.8 或更低版本滚动升级到新版,详见 PD issue #3366

  • 对于其他情况,请将上述命令执行结果反馈到 AskTUG 论坛

使用 TiCDC 同步消息到 Kafka 时 Kafka 报错 Message was too large,该如何处理?

v4.0.8 或更低版本的 TiCDC,仅在 Sink URI 中为 Kafka 配置 max-message-bytes 参数不能有效控制输出到 Kafka 的消息大小,需要在 Kafka server 配置中加入如下配置以增加 Kafka 接收消息的字节数限制。

broker 能接收消息的最大字节数 message.max.bytes=2147483648 broker 可复制的消息的最大字节数 replica.fetch.max.bytes=2147483648 消费者端的可读取的最大消息字节数 fetch.message.max.bytes=2147483648

TiCDC 同步时,在下游执行 DDL 语句失败会有什么表现,如何恢复?

如果某条 DDL 语句执行失败,同步任务 (changefeed) 会自动停止,checkpoint-ts 断点时间戳为该条出错 DDL 语句的结束时间戳 (finish-ts) 减去一。如果希望让 TiCDC 在下游重试执行这条 DDL 语句,可以使用 cdc cli changefeed resume 恢复同步任务。例如:

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 语句:

cdc cli changefeed remove --server=http://127.0.0.1:8300 --changefeed-id simple-replication-task
cdc cli changefeed create --server=http://127.0.0.1:8300 --sink-uri="mysql://root:123456@127.0.0.1:3306/" --changefeed-id="simple-replication-task" --sort-engine="unified" --start-ts 415241823337054210

使用 TiCDC 同步消息到 Kafka 时报错 kafka: client has run out of available brokers to talk to: EOF,该如何处理?

该问题通常是由于 TiCDC 与 Kafka 集群连接失败导致。你可以通过检查 Kafka 的日志以及网络状况来排查。一个常见的原因是在创建同步任务时没有指定正确的 kafka-version 参数,导致 TiCDC 内部的 Kafka client 在访问 Kafka server 时使用了错误的 Kafka API 版本。你可以通过配置 --sink-uri 指定正确的 kafka-version 参数来修复。例如:

cdc cli changefeed create --server=http://127.0.0.1:8300 --sink-uri "kafka://127.0.0.1:9092/test?topic=test&protocol=open-protocol&kafka-version=2.4.0" 

TiCDC 故障处理更新于 2024/3/13 14:47:09: ticdc: Add kafka eof troubleshooting (#16777) (#16815)

1 个赞