TiDB HTAP 上手指南丨添加 TiFlash 副本的工作原理

2021-11-02 12:37:07 浏览数 (1)

TiFlash 是 TiDB HTAP 形态的关键组件,它是 TiKV 的列存扩展,在提供了良好的隔离性的同时,也兼顾了强一致性。列存副本通过 Raft Learner 协议异步复制,但是在读取的时候通过 Raft 校对索引配合 MVCC 的方式获得 Snapshot Isolation 的一致性隔离级别。这个架构很好地解决了 HTAP 场景的隔离性以及列存同步的问题。

使用 TiFlash 前,需要给表添加 TiFlash 副本。不少用户反馈添加 TiFlash 副本的时候出现问题。TiFlash 副本始终处于不可用状态官方文档总结了一些简单的问题排查。

这篇文章将介绍目前版本(目前所有 release 的 4.x, 5.x 版本)下给 TiDB 中的表添加 TiFlash 副本的工作原理,主要供 DBA 同学们排查相关的问题时,可以从中参考先从哪些方面收集信息及尝试解决。

基本概念

在 PD 的视角里,TiFlash 实例与 TiKV 实例类似,都是一个 store,只是 TiFlash 的 store 会带有 “key=engine, value=TiFlash” 的一个 label。添加 TiFlash 副本后,PD 把 region 调度到 TiFlash,并让其中的 region 一直只以 learner 的形式存在,依赖的是 Placement Rules 功能

TiFlash 实例中包含有一个修改版本的 TiKV 代码,主要负责与 TiKV 协同处理 Raft 层的操作,其输出日志与 TiKV 基本一致。TiUP 部署时,其日志会输出到 tiflash_tikv.log。

TiFlash 实例会定期启动一个子进程来处理与 TiFlash 副本添加、删除相关的操作。如果在进程列表中偶尔看到一个名为 tiflash_cluster_manager 的不常驻进程(在官网中称为 “pd buddy”),属于正常情况。其日志会输出到 tiflash_cluster_manager.log。

TiFlash 内部组件架构图

添加 TiFlash 副本各阶段

集群中组件的工作

添加 TiFlash 副本的时序图

执行副本数修改 DDL

在 TiDB 中执行 `alter tableset tiflash replica` 时,这条语句作为 DDL 语句执行。

从 progress 0.0 到 1.0 的同步过程中

TiDB 提供 http 接口,其他组件可以通过此接口查询哪些表存在 TiFlash 副本:`curl http://:/tiflash/replica`。

TiFlash 有定期任务,负责:

  1. 从 TiDB 的 tiflash/replica 接口拉取哪些表/分区有 TiFlash 副本。对于未 available 的表,如果表在 PD 上没有相应的 Placement Rules,该任务会负责设立相应的 rule,key range 为 [ t__r, t__ )。
  2. 对于未 available 的表,该任务会从 PD 拉取 key range 对应的 region_id,以及在线的所有 TiFlash store 中有多少已经同步的 region_id。
  3. 以 TiFlash store 中去重后的 region_id 个数 PD 中 region_id 个数,通过给 tiflash/replica 接口发 POST 请求的方式更新同步进度 progress。
  4. 如果 PD 中存在 placement-rules 但 tiflash/replica 中不存在相应的 table_id,说明该表/分区已经被 DROP 而且已经过了 GC 时间,会到 PD 中移除相应的 rule。

该组件的日志输出为 tiflash_cluster_manager.log。如果集群中存在多个 TiFlash,会通过 PD 内置的 etcd 选出一个来负责上述任务。通过日志排查时需要拿到该时间段内负责该工作的节点,或者拿全部 TiFlash 节点的相关日志。

PD 的行为:接收到 placement-rules 后,PD 会:

  1. 先对 Region 进行切分,确保 Region 的边界不会跨越 表数据 及 索引(因为 TiFlash 只同步表数据部分)
  2. 对 Region 的 Leader 下发 AddLearner 到 TiFlash store 的调度

TiKV 的行为

  1. TiKV 中 Region 的 Leader 接受并执行 PD 的 AddLearner 命令
  2. Region Leader 以 Snapshot 形式把 Region 数据发送到 TiFlash 的 Region peer

对于已经有 TiFlash 副本的分区表进行 Add partition 的过程

TiDB 对已经有 TiFlash 副本的分区表进行 Add partition 时,会在生成 partition 后(但对用户不可见)block 并等待。直到 TiFlash 上报该 partition 对应的 partition_id 已经 available 后,DDL 才执行完成。(详细内容可参考 TiDB 相关 PR

对于 TiFlash 而言,给分区表添加一个 partition 与添加一个普通表是类似的操作,可以参考上文的流程。不同的是在此情况下,会额外在 PD 添加 accelerate-schedule 的操作,提升分区表 key range 相关 Region 的调度优先级,以期望在集群繁忙的情况下,缩短分区表的 available 速度,减少 DDL block 的时间。

为什么需要 block 分区表的 Add partition 操作

  • 假如不 block Add partition 的 DDL 操作,在用户执行查询语句时(比如 count(*) ),如果查询选择了从 TiFlash 读,但是新 partition 上的 region 还没有建立起 TiFlash 副本,此时会导致用户的查询因为少数的 region 而失败。表现出来为用户在执行 Add partition 时,查询该表不稳定,容易失败。
  • 为了避免造成查询的不稳定,block 分区表的 Add partition 操作,待新建分区的 Region 建立完 TiFlash 副本 ready 后才允许读到该分区。

不同阶段出现问题时排查的方向(举例)

执行 `alter tableset tiflash replica` 时卡住

通常来说,这句 DDL 操作仅修改 TiDB 中的元信息,执行时不会阻塞太久。如果出现执行此语句卡住的问题,可以看是否有其他 DDL 操作 block 了该语句的执行(比如在同一个表上是否存在 add index 操作)。更多地可以参考其他 TiDB 中 DDL 卡住的经验 [FAQ] DDL 卡住排查经验 - TiDB 常见 FAQ

副本数修改成功,但是 progress 一直为零,或者 progress 有进展,但是很 “慢”

  • 先根据 TiFlash 副本始终处于不可用状态确认下基本的问题
  • 上述排查无误的情况下,先检查 tiflash_cluster_manager.log 的日志。看是否与 TiDB 或 PD 连接出现异常,如果有异常,先确认是相关组件的 API 查询超时(curl http://:10080/tiflash/replica,见TiDB 与 TiFlash 同步接口)还是网络连通性有问题。
  • 再确认出现问题的表是否有创建 placement-rule (tiflash_cluster_manager.log 日志中关键字 “Set placement rule … table--r”),上报给 TiDB 的进度信息(id, region_count, flash_region_count)。确认 PD 上是否能够查询到相应表的 rule (参考Placement Rules 使用文档 )。
  • 确认同步进度 “慢” 的具体表现。出问题的表,其 flash_region_count 是否很长时间”没有变化”,还是只是 “变化得慢” (比如几分钟还是会涨几个 region)。
  • 如果是 “没有变化”,需要排查整个工作链路上什么环节出现问题。 TiFlash 给 PD 设 rule -> PD 给 TiKV 中的 Region leader 下发 AddLearner 调度 -> TiKV 给 TiFlash 同步 Region 数据 这个链路是否有问题,收集相关组件的日志进行排查。 可以检查 tikv、tiflash-proxy 日志中的 warn/error 信息,确认是否存在网络隔离之类的错误。
  • 如果是 “变化得慢”,可以排查 TiFlash 当前的负载、PD 的调度。 主要观察  Grafana 中的 TiFlash-Summary 看板,Raft 中 “Applying snapshots Count”、“Snapshot Predecode Duration”、“Snapshot Flush Duration” 几个图,反映 TiFlash 通过 ApplySnapshot 接收数据的并发度、apply 耗费的时长;以及 Storage Write Stall 中的 “Write Stall Duration” 是否写入太频繁,导致出现了 Write Stall 现象;收集其他如CPU、磁盘IO负载等,以及 TiFlash 的日志。 PD 相关的调度参数调整见:PD 调度参数

对已经有 TiFlash 副本的分区表进行 Add partition 过程中卡住

根据 PR 中的 comment,如果是因为 TiFlash 没有建立起副本而 block 住,会打印 “[ddl] partition replica check failed” 的日志。接下来的排查方向,大概是当时的是否有较多 Region 在建立 TiFlash 副本、TiFlash apply snapshot 的压力、PD 调度优先级是否有生效等。

附录:

一些过程中辅助排查的 API:

TiDB 中查询 TiFlash 副本、进度等

select * from information_schema.tiflash_replica

查看最近 执行 pending 的 DDL 任务

admin show ddl jobs

TiDB 中获取 TiFlash 副本消息的 API 接口(与 TiFlash 交互的主要接口)

curl http://:/tiflash/replica

TiDB 中查询表的 Region 信息

SHOW TABLEREGIONS;

查询单个 TiFlash 节点上 table_id 对应的 Region 信息

echo "DBGInvoke dump_all_region(,true)" | curl "http://:/?query=" --data-binary @- 

PD 中查询 Region 的信息

tiup ctl pd -u http://:region

PD 中查询 Placement-rules 信息

tiup ctl pd -u http://:config placement-rules show

0 人点赞