TiCDC 的集群性问题
TiCDC Cluster Metrics
如何通过监控判断 CDC 集群, CDC 集群级别是否存在性能问题,可以看以下监控:
- uptime:指的是集群当中的每一个节点运行时长。若 uptime 呈断续状态,则可推测这个节点出现异常情况:如可能存在 OOM / Panic 等问题。此时,应到这台节点对应的机器获取相应日志,或查看系统的 OOM 记录,并向技术团队报 issue,提 bug。
- CPU Usage & Memory Usage:若 CPU Usage、Memory Usage使用量处于较高水平时,可判定整个集群处于不健康的状态,即集群资源不足。资源不足与任务负载情况相对应,若任务负载过重,但是却使用配置为 4C 8G 甚至更低配置的机器,显然机器资源无法满足需求,此时应主动扩机器。若机器资源配置已经非常高,CPU 使用率仍居高不下,可使用 pproof 抓去 CPU 和内存的性能分析数据。
- Ownership history & PD leader history:这两项监控显示了在当前时刻或历史时间序列中 Owner 节点、 PD 节点信息。若 Owner 节点、PD 节点发生过切换,需查询发生切换的原因。例如,是否因当前 Owner 节点遭遇故障引发切换,此类问题均可通过查看日志的方式排查。 PD leader 亦是如此, PD leader 的切换会对所有需要访问它的组件产生影响, 比如 CDC 组件需要访问 PD leader 以获取到当前的时间戳。若 PD 在某一时间段发生 leader 切换,在此期间它将无法对外提供服务,此时可观察到 CDC 的运行状态处于不健康状态。这一板块主要是用于检测 TICDC 集群的基础健康状态。
Changefeed 延迟分析
绝大多数情况下,我们所遇到的问题都是与 Changefeed 的延迟相关。在后续的报告中将采用 "Changefeed" 这个词,而非 "CDC",这是因为 CDC 指的是集群,而 Changefeed 指的是同步任务。
Changefeed Latency Analysis
Changefeed 的延迟主要从两个方面进行性定义,其一为 Resolved TS,其二为 Checkpoint TS。
- Resolved TS:指 CDC 从 TiKV 接收数据时产生的延迟。若该延迟上升,则可以推断是 TiKV-CDC 模块(即 TiKV 上负责向 CDC 发送数据的模块)内部产生了延迟。另一种可能的情况是,Changefeed 内部的 KV-Client / Puller / DB Sorter 等模块在搜数据时产生了延迟。如观察到 Resolved 的 TS 上升,就需要查 TiKV-CDC、KV-Client、Puller、DB Sorter 部分的健康状态。
- Checkpoint TS:若 Resolved TS 未出现上升处于平缓的状态。此时需探究 Checkpoint TS 上升的原因。通常是由于向下游系统发数据的速度过慢所致。数据发送慢可能是由网络延迟高引起,也可能是因为待发送的数据量过大。在此情形下,需要查看的监控指标包括 DB Sorter 读数据的的部分,以及 Sink 模块中 General、MQ、MySQL 来查相应的延迟情况。
TiCDC Cluster Metrics
在 CDC 的监控体系中第一栏存在"analyze 延迟分析"的内容。
第一列 checkpoint log 和 resolved ts log 大家已有一定的了解。从图示可以观察到 resolved ts 呈现波动状态但延迟水平并不高。据此,我们可以初步判断 CDC 和 TiKV 之间基于 GR 协议的匹配通信不存在大的问题。但既然存在波动,需进一步探究。这里涉及到 "Eventfeed error",若其存在内容,即表明这发生报错,这通常意味着 TiKV 上的 region 发生过剧烈的变化,或是迁移至其他的 TiKV 节点,导致 resolvd ts 抖动。
倘若在左侧监控数据中发现 checkpoint 的 lag 在持续上升,而 resolved ts 未上升,那极有可能是数据写入下游耗费时间过长所致。这个推断可以通过 "Sink write rows" 这一指标佐证,该指标表示每秒 sink 向下游发送的数据量,数值约为二十几万条 / 秒即表明系统正在向下游写入数据,且写入速度达到每秒二十多万条。但即便如此,延迟仍然较高,由此可推断是待写入的数据总量过大。这便是基于该监控数据进行判断的基本思路。
然而如果在监控中发现 “Sink write rows” 数值极低,与此同时延迟却居高不下,那么大概率是 sink 模块出现问题,导致数据无法正常写入。在这种情况下应当优先对 sink 模块排查,可通过查看 sink 内部的日志,或者检测网络延迟情况。
Changefeed latency analysis
-
Resolved Ts lag:
- 查 scheduler 看是否存在调度
- 查 TiKV 看是否存在增量扫
-
Checkpoint lag:
- 查 scheduler 是否存在调度
- 查 Sink 模块是否出现瓶颈
- 查 changefeed 状态,看是否出现错误,查日志
Changefeed metrics
我们需深入分析 Changefeed 数据呈现断断续续状态的原因。
首先观察 changefeed 的运行状态,发现其始终处于正常同步状态。在 changefeed 监控面板中 "The status of changefeeds" 指的是在当前时刻或历史序列中 changefeed 的异常记录,从该记录中我们可以看到它一直维持 normal 状态。
与之对应的是 changefeed tables count 持续增加,每隔几分钟便会出现一次增长,且对应 Executed DDL Count/Minutes。changefeed 同步表数量逐步增加,说明该时段内存在诸如 Create table 或 Truncate table 语句正在被执行的。当上游执行 create table 操作后, CDC 接收该指令,并将此 DDL 发送至下游。与此同时,其自身的 scheduler 会去调度任务,将新创建的表调度到某个 CDC 节点进行同步处理,由此便导致了相关数据指标上升的态势。
之前提到当 scheduler 执行表调度任务时,无法推进 checkpoint,这正是导致数据呈现断断续续状态的原因。通过观察数据曲线,我们可以发现每一个数据波动的 “小山丘” 所对应的时间,均能与一条斜线相对应。这一现象充分说明 resolved ts 的延迟正是由加载表所引发。
在正常情况下,若集群处于健康状态,通常不会对表进行调度操作。仅在执行Create Table、 Drop Table 和 Truncate Table 这三种情况时才会出发表调度。其中,Create Table 操作为向系统中新增一张表,Drop Table 则是从系统中删除一张表。从资源角度而言,Create Table 所需的开销较大,因其涉及到资源分配等一系列复杂操作;而 Drop Table 操作相对轻量,主要是停止相关任务,并释放所有占用的资源,故开销较小。Truncate Table 操作较为特殊,其实质为一次 Drop Table 操作与一次 Create Table 操作的组合,因此在这三种操作中,其资源开销最大。若集群中存在大量且频繁的周期性 Truncate 语句,便会频繁观测到 resolved ts 指标上升。
基于此给出如下建议:若能够明确定位哪些表需要周期性地执行 Truncate 操作,可将这些表单独置于一个 Changefeed 中进行同步;而将无需进行 Truncate 操作的表,统一放在另一个 Changefeed 中。通过这种方式,可确保无需进行 Truncate 操作的表在数据同步过程中,运行状态更为平稳。
Scheduler metrics
Scheduler metrics 记录了 changefeed 内部 scheduler 模块的运行状况,以及每张表当前的同步状态。在此记录体系下,一张表存在如下几种生命周期状态:
- Absent 状态:该表当前尚未被加载,处于缺失状态。若表处于此状态,其 changefeed 与 checkpoint 均无法推进,后续需对该表执行调度操作。
- Commit 状态:该表已完成加载。
- Prepare 状态:该表正在从上游进行数据拉取操作。
- Removing 状态:该表需要被停用;此外,当表发生调度,从 a 节点调度至 b 节点的过程中,也会呈现此状态。
- Replicating 状态:该表正处于受控同步进程之中 。
特别值得关注的是 slowest table ID,即最慢表的标识及其状态。此前,不少人提出过这样的问题:在 changefeed 同步众多表的过程中,可能会被某一张表阻碍进度。在此情形下,通过查看 slowest table ID,便能知晓具体是哪一张表造成了阻塞。例如,若最慢表的 ID 为 111 ,那么可前往上游进行查询,或查阅 CDC 的日志,以确定 ID 为 111 的表的具体名称,进而在上游分析该表是否存在特殊情况。比如,该表的数据量是否极为庞大,或者是否在某一时间段内短时间内写入了大量数据。若只是一次性短时间写入大量数据,可暂时不予理会,因其最终能够逐渐完成数据处理。然而,若该表每日,或按每周、每月等周期性规律,均会出现大规模的数据写入高峰,那么就需要考虑将这张表单独分离出来,以避免对其他表产生影响。
这便是 slowest table ID 所具有的重要价值。这部分内容是 scheduler 中需要重点理解的关键要点,其概念相对易于理解,且在实际操作中易于上手。综上所述,我们对 resolve 的 TS 和全部 TS 上升的基本情况进行了分析,在此可以进行一个总结:check point log 极为关键,其反映的是已发送至下游的数据量,这恰恰是用户最为关切的问题,因为用户往往并不关注数据的拉取量,而是着重关心下游集群当前接收到的数据量。
Checkpoint Lag increase
Checkpoint Lag increase 这一指标具有重要的意义,其核心反映的是已成功传输至下游的数据量,而这一数据量信息恰恰是用户在整个数据流转过程中最为关注的要点。Checkpoint 出现上升趋势的原因,通常可归纳为以下两大主要类别:
-
Resolved ts 推不动,导致 TiCDC 没有主动地推动数据到下游
- 表调度,期间不能推进 Resolved Ts 和 Checkpoint
- Resolved Ts 卡住,如大量增量扫无法及时完成
-
TiCDC 主动推送数据到下游,但是推不动,比如下游出现异常
- 从 DB Sorter 读数据慢,理论上存在,实际上从未遇到过。
- MySQL Sink:写 SQL 延迟高,SQL 语句报错等
- Kafka Sink:发送数据到 Kafka 延迟高
DB Sorter
TiCDC 的内部架构中,存在一个名为 sorter 的模块,其基于数据库技术实现。该模块的基本工作原理如下:当从上游的 TiKV 接收到行变更数据后,系统会将这些数据写入 CDC 集群的磁盘中,一旦完成这一写入操作,即可认定 CDC 已成功接收该部分数据,此时相应的数据被标记为 resolved,进而可以推进 resolved TS。
在向下游发送数据时,首先需要从 DB sorter 模块中读取数据,随后再将其发送至下游。由此可见,DB Sorter 的性能表现对整个数据传输流程至关重要。在正常运行状态下,该模块的读写速率通常极为高效。然而,倘若监测到 DB Sorter 的读写延迟显著升高,并导致 checkpoint 或 resolved TS 出现严重延迟的情况,就需要对承载该模块的机器磁盘性能进行全面排查。从理论层面看,DB Sorter 的读写速度若出现缓慢状况,必然会对数据传输延迟产生影响。但值得注意的是,在实际的项目实践中,尚未出现过因 DB Sorter 读写过慢而引发问题的案例 。
Write duration 指的是向 DB Sorter 写入数据所产生的基本延迟,通常维持在毫秒级。其写入速度极为迅速,可达每秒数百兆字节。同样,从 DB Sorter 读取数据时产生的延迟也在毫秒时间范围内 。
Sink metrics
如何判断 sink 写得慢不慢?
Memory Quota:changefeed 级别的配置项,默认 1G,其主要作用在于规避系统出现 OOM 的情况。若在监控过程中发现 Memory Quota 始终处于饱和状态,即可明确判定下游环节构成瓶颈。瓶颈指发送速率相较于接收速率处于较低水平,然而这并不意味着发送速率本身必然极低,它很可能本身吞吐性能颇好。
在此情形下,可能会提出疑问:若将 Memory Quota 增大至 2G、3G,是否能够产生积极效用?依据个人经验判断,此种做法并无实际意义。Memory Quota 存在的核心意义在于防止 OOM,而数据吞吐的上限实则受制于发送方与接收方之间的网络延迟,或是接收方自身的数据处理性能。
Output Row Count / Second:每秒发送到下游的数据量。
Executed DDL Count / Minute:每秒 DDL 执行的数量。
Kafka Sink Metrics
在日常排查所涉及的诸多记录中内容较为繁杂,其中需重点关注 Kafka Request Latency 这一指标,它主要用于衡量从 changefeed 向位于下游的 Kafka 集群发送单条数据时所产生的网络延迟情况。
在内部的测试环境当中,通常情况下此延迟在五毫秒以内,多数情况下可达微秒级别。然而,一旦该延迟较高,如15 毫秒、 20 毫秒、 50 毫秒乃至 100 毫秒,极有可能对系统的吞吐性能产生极为显著的影响,这是由于该延迟的变化往往会致使其他相关指标出现异常波动。
MySQL Sink Metrics
- Conflict Detect Duration:该指标用于检测事务之间的冲突。
- Full Flush Duration:若 Full Flush Duration 数值显著偏高,表明当前正在执行的这个事务规模庞大,亦或是下游的 TiDB MySQL 存在瓶颈,导致无法及时处理 SQL 请求。当此部分延迟较高时,会反向影响 Conflict Detect Duration 的延迟情况。这是因为大量待发送的事务会在 Conflict Detect Duration 模块中排队等待处理。由于事务向下游发送的速度减缓,事务排队时间延长,需要进行冲突消解的事务数量不断增多,进而导致 Conflict Detect Duration 时长增加。因此,若出现 MySQL Sink 速度缓慢的问题,首先应着重解决 Full Flush Duration 相关问题。
- Worker Busy Ratio:该指标用于衡量 MySQL Sink 内部的繁忙程度。
TiKV-CDC 模块
TiCDC Architecture
在探究 TiCDC 的内部机制时应着重关注 TiKV 和 TiCDC 之间的关系:
TiCDC 通过 GRPC 协议从 TiKV 拉取数据。具体而言,TiKV 和 TiCDC 之间借助 gRPC 进行通信。在 TiKV 层面,存在一个名为 TiKV - CDC 的模块,该模块主要承担向外部提供事件变更信息的职责,扮演着 server 的角色。而 TiCDC 则以 client 的身份参与其中。在每个 changefeed 内部,设有一个名为 KV client 的模块。当 KV client 判定其所需数据位于某一特定的 TiKV 节点时,便会发起一个请求。首先,KV client 会与该 TiKV 节点建立一条 gRPC 双向连接,之后在该连接上发送请求以获取数据,此时,TiKV - CDC 模块便会将相应数据传输给 TiCDC 。
Event Scan
TiKV所发送过来的数据包含以下两种类型:
- Incremental Scan:通常被称为增量扫,其原理是对存储于磁盘上的 RocksDB 中的部分数据进行扫描操作。
- Real-time Scan:即实时扫,其工作机制是在事务被写入到 TiKV 的过程中,将该事务中的内容同步发送一份至 CDC。相较于 Incremental Scan,Real - time Scan 具有显著的时效性优势,能够更快地将数据变动同步至 CDC。在实际应用场景中,绝大多数的数据同步问题往往集中在 Incremental Scan 方面。
Event Type
TiKV 会向 CDC 发送多种类型的信息,具体如下:
- Change event:该类消息用于传递数据的变动情况,涵盖数据的插入、更新、删除等操作所产生的事件信息,确保 CDC 能够及时捕捉到数据的变化,以维持数据的一致性和实时性。
- Resolved Ts:此消息代表已解析的时间戳,通过该时间戳,CDC 能够标记已处理的数据状态,从而保证数据处理的顺序性与完整性,为后续的数据同步和处理提供关键的时间标记依据。
- Error event: 这类消息属于内部信息,下游的消费者如 MySQL 等数据库无法获取此类信息之类,仅 CDC 内部的 KV client 能够知晓。当 KV client 正在订阅某个 region,或者与 TiKV 节点进行交互时,若遭遇各类错误,便会生成 Error event 消息。CDC 内部会自动触发相应的错误处理机制,对这些错误进行处理。通过我们最初展示的监控系统,能够清晰地观测到这些错误信息,从而为运维人员提供关键的问题排查线索,助力其快速定位并解决问题 。
在 TiKV 与 CDC 的交互过程中,可能出现的错误类型如下:
- EpochNotMatch:Region 发生了合并或分裂操作。
- RegionNotFound:维护 region 信息的 region cache 模块尚未更新,找不到特定的 region,一般发生在 region 发生变化的场景,如迁移,合并等。
- NotLeader:当前 region peer 不是 leader,说明发生了 region transfer。
- ServerIsBusy:TiKV-CDC 上增量扫任务个数,超过默认的 incremental_scan_concurrency_limit,默认 10000。
- Congested:该错误是在 v8.4.0 中引入,产生原因是 TiKV-CDC 的 Memory Quota 超过了配额,触发了熔断机制。
TiKV-CDC Key Configurations
这里列了几个比较重要的 TiKV-CDC的配置项:
Configuration | Default value | Usage |
cdc.sink-memory-quota | 512 MiB | TiKV-CDC 内存开销大的部分的整体配额。 在遇到大流量写入的情况下,特定 region 尝试发送数据可能发生超过 memory quota 的情况,此时该 region 被熔断,即订阅任务被取消,返回 Congested 错误到 TiCDC,TiCDC 重新订阅该 region 触发增量扫 |
cdc.incremental-scan-concurrency | 6 | 某一时刻正在执行增量扫的任务数量。该数量大于线程池数量,因为增量扫任务可能在执行过程中发生上下文切换 |
cdc.incremental-scan-threads | 4 | 执行增量扫任务的线程池中的线程数量 |
- cdc.sink-memory-quota:其默认值为 512 兆,在集群运行过程中,若遭遇大流量写入操作,且经观察发现 TiKV - CDC 模块的内存占用水位极高,此时可对该参数值进行适当调大。需特别注意的是,此项操作应选择在系统相对空闲的时段进行,如此方能有效规避因大流量写入引发的熔断及重新订阅问题,进而避免因上述问题导致的 resolved ts 上升情况。
- cdc.incremental-scan-threads:默认配置为启用 4 个线程执行增量扫描任务,然而其并发数却设定为 6。之所以出现 4 个线程同时处理 6 个任务的情况,是因为每个任务在线程上执行时,不可避免地会发生上下文切换,这一过程会消耗一定时间与系统资源。为了在有限的线程资源下,尽可能提升任务处理效率,并发数的设定会稍大于线程数量。在绝大多数正常运行场景中,该默认配置能够满足系统需求,无需对其进行调整。但倘若在集群监测过程中,发现增量扫描任务数量庞大且长时间无法完成,此时则可考虑对该参数进行合理调整。
TiKV-CDC Metrics
TiKV-CDC 的监控主要集中于 CDC 的 TiKV 模块之下,以下为其中较为关键的要点:
TiKV-CDC CPU
Endpoint 最大值为100。若 Endpoint 被打满,由此可推断出 TiKV - CDC 的性能存在短板,成为了系统运行的瓶颈。而 Workers 的默认值为四百,当该数值被打满,意味着当前正在执行的增量扫描任务极为繁重,即便所有 worker 均处于满负荷运转状态,也无法及时完成任务。这表明系统面临着较大的计算压力,可能需要对相关资源配置或任务调度策略进行优化调整。
CDC network traffic
该指标反映的是从 TiKV 到 CDC 的网络流量状况。倘若此指标数值极低,通常存在两种可能性:其一,集群内部本身并无大量数据需要传输,即数据产生量处于较低水平;其二,网络延迟现象极为严重,极大地阻碍了数据的正常传输。
在数据传输路径中,TiKV - CDC 将数据发送至 changefeed 的 KV client,随后 KV client 通过 puller 将数据写入到 DB sorter。在此过程中,存在一条反压路线。具体而言,若 DB sorter 的处理速度迟缓,那么 KV client 的数据写入速度也会随之降低;而 KV client 写数据变慢,又会导致其从 TiKV - CDC 搜索数据的速度减缓;最终,TiKV - CDC 的数据发送速度也会受到影响而变慢。任何一个环节出现性能瓶颈,都可能通过反压机制影响整个数据传输流程的效率。
TiKV-CDC Captured region count
当前,正处于 changefeed 监测范畴内的 region 数量,对于数据同步与处理进程意义重大。在这一过程中,仅当 unresolved 数量降为零,即表明所有 region 均已成功完成订阅流程,且达成了 resolved 状态。所谓达成 resolved 状态,具体是指针对该 region 的增量扫任务全面完成。唯有在满足上述条件的情况下,TiKV - CDC 才会向 changefeed 发送 resolved ts 事件,以此推动后续数据处理环节的有序开展 。
TiKV-CDC CPU Memory
在这个监控面板中,黄色线条所代表的 Sink 指标值得我们重点关注。此即前文提及的 Sink memory quota,其最大值设定为 512 兆字节。当前显示的数值处于 KB 级别,这是由于其内存的申请与释放进程极为迅速,以至于几乎难以直观观察到相应变化。倘若在集群监控过程中,发现以 Sink 开头的这一监控指标长期处于较高水位,例如其上限为 512,而该指标长期维持在 400 以上,那么就有必要对 quota 进行适度调大。此举旨在有效规避因突发流量洪峰到来而可能导致的数据传输中断现象。
old value 主要隶属于 TiKV - CDC 内部的一个特定模块,其默认值设定为 512 兆字节。在绝大多数情况下,该模块的内存使用几乎处于饱和状态。old value 模块的主要功能在于辅助查找 old - value,即 update 事件中的旧值信息。
TiKV-CDC Incremental scan tasks
在评估集群中增量扫任务的执行状态时,需着重关注相应的监测指标与可视化呈现:
如图 Incremental scan tasks count 黄色线条代表 pending 人物状态,绿色线条则代表 ongoing 人物状态。
- Ongoing:图中 ongoing 的 Max 值为 6。这一数值与系统中预先配置的 concurrency 相对应,表明在当前的系统设置下,最多允许同时执行 6 个增量扫描任务。
- Pending:当观察到 pending 数值显示为 2004 时,这意味着当前集群中存在 2,004 个增量扫描任务处于等待处理的状态。值得注意的是,若正在执行的 6 个 ongoing 任务处理速度迟缓,那么处于 pending 状态的这 2,004 个任务的排队等待时间将会显著延长。
TiKV-CDC Incremental scan speed
增量扫本质上是对 RocksDB 存储于磁盘中的数据进行读取操作,其核心在于衡量磁盘扫描的速率。该速率直接关联到增量扫描任务的完成时效,若磁盘扫描速度极为迟缓,必然导致增量扫所需的时间大幅延长。
在数据处理流程中,增量扫的完成情况对 Resolved Ts 的推进有着至关重要的影响。当增量扫耗时增加,Resolved Ts 的延迟上升时长也会相应变长。这一连锁反应会对整个数据同步和处理的时效性产生显著影响,因此,增量扫的磁盘读取速率无疑是一项极为关键的指标 。