{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/principle_of_adding_a_tiflash_copy",
    "result": {"pageContext":{"blog":{"id":"Blogs_311","title":"TiDB HTAP 上手指南丨添加 TiFlash 副本的工作原理","tags":["TiFlash"],"category":{"name":"产品技术解读"},"summary":"本文将会介绍在目前所有 release 的 4.x, 5.x 版本下给 TiDB 中的表添加 TiFlash 副本的工作原理。DBA 同学们在排查相关的问题时，可以从中获取参考。","body":"**TiFlash 是 TiDB HTAP 形态的关键组件**，它是 TiKV 的列存扩展，在**提供了良好的隔离性的同时，也兼顾了强一致性**。列存副本通过 Raft Learner 协议异步复制，但是在读取的时候通过 Raft 校对索引配合 MVCC 的方式获得 Snapshot Isolation 的一致性隔离级别。这个架构很好地解决了 HTAP 场景的隔离性以及列存同步的问题。\n\n使用 TiFlash 前，需要给表添加 TiFlash 副本。不少用户反馈添加 TiFlash 副本的时候出现问题。[TiFlash 副本始终处于不可用状态](https://docs.pingcap.com/zh/tidb/stable/troubleshoot-tiflash#tiflash-%E5%89%AF%E6%9C%AC%E5%A7%8B%E7%BB%88%E5%A4%84%E4%BA%8E%E4%B8%8D%E5%8F%AF%E7%94%A8%E7%8A%B6%E6%80%81)官方文档总结了一些简单的问题排查。\n\n这篇文章将介绍**目前版本**（目前所有 release 的 4.x, 5.x 版本）**下给 TiDB 中的表添加 TiFlash 副本的工作原理**，主要供 DBA 同学们排查相关的问题时，可以从中参考先从哪些方面收集信息及尝试解决。\n\n## 基本概念\n\n在 PD 的视角里，TiFlash 实例与 TiKV 实例类似，都是一个 store，只是 TiFlash 的 store 会带有 “key=engine, value=TiFlash” 的一个 label。添加 TiFlash 副本后，PD 把 region 调度到 TiFlash，并让其中的 region 一直只以 learner 的形式存在，依赖的是 [Placement Rules 功能](https://docs.pingcap.com/zh/tidb/stable/configure-placement-rules#placement-rules-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3)。\n\nTiFlash 实例中包含有一个修改版本的 TiKV 代码，主要负责与 TiKV 协同处理 Raft 层的操作，其输出日志与 TiKV 基本一致。TiUP 部署时，其日志会输出到 tiflash_tikv.log。\n\n**TiFlash 实例会定期启动一个子进程来处理与 TiFlash 副本添加、删除相关的操作**。如果在进程列表中偶尔看到一个名为 tiflash_cluster_manager 的不常驻进程（在官网中称为 “pd buddy”），属于正常情况。其日志会输出到 tiflash_cluster_manager.log。\n\n![1.png](https://img1.www.pingcap.com/prod/1_7f8275a981.png)\n<center>TiFlash 内部组件架构图</center>\n\n## 添加 TiFlash 副本各阶段集群中组件的工作\n\n![20211029-174912.png](https://img1.www.pingcap.com/prod/20211029_174912_b526cee36f.png)\n<center>添加 TiFlash 副本的时序图</center>\n\n### 执行副本数修改 DDL\n在 TiDB 中执行 `alter tableset tiflash replica` 时，这条语句作为 DDL 语句执行。\n\n### 从 progress 0.0 到 1.0 的同步过程中\nTiDB 提供 http 接口，其他组件可以通过此接口查询哪些表存在 TiFlash 副本：`curl http://:/tiflash/replica`。\n\nTiFlash 有**定期任务**，负责：\n\n1. 从 TiDB 的 /tiflash/replica 接口拉取哪些表/分区有 TiFlash 副本。对于未 available 的表，如果表在 PD 上没有相应的 Placement Rules，该任务会负责设立相应的 rule，key range 为 [ t__r, t__ )。\n\n2. 对于未 available 的表，该任务会从 PD 拉取 key range 对应的 region_id，以及在线的所有 TiFlash store 中有多少已经同步的 region_id。\n\n3. 以 TiFlash store 中去重后的 region_id 个数 / PD 中 region_id 个数，通过给 /tiflash/replica 接口发 POST 请求的方式更新同步进度 progress。\n\n4. 如果 PD 中存在 placement-rules 但 /tiflash/replica 中不存在相应的 table_id，说明该表/分区已经被 DROP 而且已经过了 GC 时间，会到 PD 中移除相应的 rule。\n\n该组件的日志输出为 tiflash_cluster_manager.log。如果集群中存在多个 TiFlash，会通过 PD 内置的 etcd 选出一个来负责上述任务。通过日志排查时需要拿到该时间段内负责该工作的节点，或者拿全部 TiFlash 节点的相关日志。\n\n**PD 的行为：接收到 placement-rules 后**，PD 会：\n\n1. 先对 Region 进行切分，确保 Region 的边界不会跨越 表数据 及 索引（因为 TiFlash 只同步表数据部分）\n\n2. 对 Region 的 Leader 下发 AddLearner 到 TiFlash store 的调度\n\n**TiKV 的行为：**\n\n1. TiKV 中 Region 的 Leader 接受并执行 PD 的 AddLearner 命令\n\n2. Region Leader 以 Snapshot 形式把 Region 数据发送到 TiFlash 的 Region peer\n\n### 对于已经有 TiFlash 副本的分区表进行 Add partition 的过程\nTiDB 对已经有 TiFlash 副本的分区表进行 Add partition 时，会在生成 partition 后（但对用户不可见）block 并等待。直到 TiFlash 上报该 partition 对应的 partition_id 已经 available 后，DDL 才执行完成。（详细内容可参考 [TiDB 相关 PR](https://github.com/pingcap/tidb/pull/18495)）\n\n对于 TiFlash 而言，给分区表添加一个 partition 与添加一个普通表是类似的操作，可以参考上文的流程。不同的是在此情况下，会额外在 PD 添加 accelerate-schedule 的操作，提升分区表 key range 相关 Region 的调度优先级，**以期望在集群繁忙的情况下，缩短分区表的 available 速度，减少 DDL block 的时间。**\n\n**为什么需要 block 分区表的 Add partition 操作：**\n\n* 假如不 block Add partition 的 DDL 操作，在用户执行查询语句时(比如 count(*) )，如果查询选择了从 TiFlash 读，但是新 partition 上的 region 还没有建立起 TiFlash 副本，此时会导致用户的查询因为少数的 region 而失败。表现出来为用户在执行 Add partition 时，查询该表不稳定，容易失败。\n\n* 为了避免造成查询的不稳定，block 分区表的 Add partition 操作，待新建分区的 Region 建立完 TiFlash 副本 ready 后才允许读到该分区。\n\n## 不同阶段出现问题时排查的方向（举例）\n### 执行 `alter tableset tiflash replica` 时卡住\n通常来说，这句 DDL 操作仅修改 TiDB 中的元信息，执行时不会阻塞太久。如果出现执行此语句卡住的问题，可以看是否有其他 DDL 操作 block 了该语句的执行（比如在同一个表上是否存在 add index 操作）。更多地可以参考其他 TiDB 中 DDL 卡住的经验 [[FAQ] DDL 卡住排查经验 - TiDB 常见 FAQ](https://asktug.com/t/topic/34386)。\n\n### 副本数修改成功，但是 progress 一直为零，或者 progress 有进展，但是很 “慢”\n\n* 先根据 [TiFlash 副本始终处于不可用状态](https://docs.pingcap.com/zh/tidb/stable/troubleshoot-tiflash#tiflash-%E5%89%AF%E6%9C%AC%E5%A7%8B%E7%BB%88%E5%A4%84%E4%BA%8E%E4%B8%8D%E5%8F%AF%E7%94%A8%E7%8A%B6%E6%80%81)确认下基本的问题\n\n* 上述排查无误的情况下，先检查 tiflash_cluster_manager.log 的日志。看是否与 TiDB 或 PD 连接出现异常，如果有异常，先确认是相关组件的 API 查询超时(curl http://:10080/tiflash/replica，见 TiDB 与 TiFlash 同步接口）还是网络连通性有问题。\n\n* 再确认出现问题的表是否有创建 placement-rule （tiflash_cluster_manager.log 日志中关键字 “Set placement rule … table--r”），上报给 TiDB 的进度信息（id, region_count, flash_region_count）。确认 PD 上是否能够查询到相应表的 rule （参考 [Placement Rules 使用文档](https://docs.pingcap.com/zh/tidb/stable/configure-placement-rules#%E4%BD%BF%E7%94%A8-pd-ctl-%E6%9F%A5%E7%9C%8B%E5%92%8C%E4%BF%AE%E6%94%B9%E6%89%80%E6%9C%89%E9%85%8D%E7%BD%AE)）。\n\n* 确认同步进度 “慢” 的具体表现。出问题的表，其 flash_region_count 是否很长时间”没有变化”，还是只是 “变化得慢” (比如几分钟还是会涨几个 region)。\n\n1. 如果是 **“没有变化”**，需要排查整个工作链路上什么环节出现问题。\nTiFlash 给 PD 设 rule -> PD 给 TiKV 中的 Region leader 下发 AddLearner 调度 -> TiKV 给 TiFlash 同步 Region 数据 这个链路是否有问题，收集相关组件的日志进行排查。\n可以检查 tikv、tiflash-proxy 日志中的 warn/error 信息，确认是否存在网络隔离之类的错误。\n\n2. 如果是 **“变化得慢”**，可以排查 TiFlash 当前的负载、PD 的调度。\n主要观察  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 的日志。\nPD 相关的调度参数调整见：[PD 调度参数](https://docs.pingcap.com/zh/tidb/stable/tiflash-configuration#pd-%E8%B0%83%E5%BA%A6%E5%8F%82%E6%95%B0)。\n\n### 对已经有 TiFlash 副本的分区表进行 Add partition 过程中卡住\n根据 [PR 中的 comment](https://github.com/pingcap/tidb/pull/18495#issuecomment-657990066)，如果是因为 TiFlash 没有建立起副本而 block 住，会打印 “[ddl] partition replica check failed” 的日志。接下来的排查方向，大概是当时的是否有较多 Region 在建立 TiFlash 副本、TiFlash apply snapshot 的压力、PD 调度优先级是否有生效等。\n\n## 附录：\n\n一些过程中辅助排查的 API：\n\n**TiDB 中查询 TiFlash 副本、进度等**  \n`select * from information_schema.tiflash_replica`\n\n**查看最近执行 / pending 的 DDL 任务**  \n`admin show ddl jobs`\n\n**TiDB 中获取 TiFlash 副本消息的 API 接口（与 TiFlash 交互的主要接口）**  \n`curl http://:/tiflash/replica`\n\n**TiDB 中查询表的 Region 信息**  \n`SHOW TABLEREGIONS`\n\n**查询单个 TiFlash 节点上 table_id 对应的 Region 信息**  \n`echo \"DBGInvoke dump_all_region(,true)\" | curl \"http://:/?query=\" --data-binary @- `\n\n**PD 中查询 Region 的信息**  \n`tiup ctl pd -u http://:region`\n\n**PD 中查询 Placement-rules 信息**  \n`tiup ctl pd -u http://:config placement-rules show`","date":"2021-10-29","author":"黄俊深","fillInMethod":"writeDirectly","customUrl":"principle_of_adding_a_tiflash_copy","file":null,"relatedBlogs":[]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}