{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/tidb-service-write-slow-analysis",
    "result": {"pageContext":{"blog":{"id":"Blogs_514","title":"最佳实践：TiDB 业务写变慢分析处理","tags":["TiDB"],"category":{"name":"案例实践"},"summary":"在日常业务使用或运维管理 TiDB 的过程中，每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题。本文针对写 TiDB 集群的场景，总结业务 SQL 在写突然变慢时的分析和排查思路，旨在沉淀经验、共享与社区。","body":"## 导读\n\n在日常业务使用或运维管理 TiDB 的过程中，每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题。这类问题大部分情况下都具有一定的规律可循，通过经验的积累可以快速的定位和优化。但是有些情况下不一定很好排查，尤其涉及到内核调优等方向时，如果事先没有对各个组件的互访关系、引擎存储原理等有一定的了解，往往难以下手。\n\n本文针对写 TiDB 集群的场景，总结业务 SQL 在写突然变慢时的分析和排查思路，旨在沉淀经验、共享与社区。\n\n相关阅读：[最佳实践：TiDB 业务读变慢分析处理](/blog/tidb-service-read-slow-analysis \"最佳实践：TiDB 业务读变慢分析处理\")\n\n## 写入原理\n\n业务对集群的数据写入流程会被 TiDB Server 封装为一个个的写事务，写事务的完成主要涉及的组件是 TiDB Server 和 TiKV Server。如下所示，是 TiDB 集群写入流程的架构简图：\n\n![TiDB 集群写入流程](https://img1.pingcap.com/files/2023/09/20230922102700182.png)\n\n事务在写入的过程，分别会与 TiDB Server、PD 和 TiKV Server 进行交互：\n\n**TiDB Server**\n\n- 用户提交的业务 SQL 经过 Protocol Layer 进行 SQL 协议转换后，内部 PD Client 向 PD Server 申请到一个 TSO，此 TSO 即为事务的开始时间 txn_start_tso，同时也是事务在全局的唯一 ID\n- 接着 TiDB Server 对 SQL 文本进行解析处理，转为抽象语法树 AST 传给下一个处理模块\n- TiDB Server 对 AST 进行编译、SQL 等价改写等逻辑优化、参考系统统计信息进行物理优化后，会生成真正可以执行的计划\n- 可执行的计划经过分析判断，点查询操作转到KV模块、复杂查询转到 DistSQL 模块（继续转为对单个表访问的多个请求），再经过 TiKV Client 模块与 TiKV 进行交互，在 TiDB Server 这一侧完成对数据的访问\n\n**TiKV Server**\n\n- TiKV 的 Scheduler Worker Pool 模块负责接收通过 gRPC 传过来的写请求数据，在这里它能实现写入流量的控制、锁冲突检查与获取（latch）、快照（snapshot）版本对比的功能\n- 前面的校验通过后，写入的数据会进入到 Raftstore Pool 模块，它会将写入数据的请求封装为 raft log （Propose ），在本地持久化（append）的同时并发分发到 follower 节点，接着完成 raft log 的 commit 操作，最后将 raft log 日志数据写入到 rocksdb raft\n- Apply Pool 模块充当消费者的的角色，会消费 rocksdb raft 里面的日志数据，转为真正的 KV 数据存储到 rocksdb KV，至此完成了一次写入数据的流程\n\t- rocksdb 里面的数据写入包括了 LSM Tree 的写入过程，主要方面有 WAL、MemTable 、Immutable Table、L0\\~L6 层的内存或磁盘 IO 操作，这里并没有详细阐述，有兴趣的可以前往官网查阅。\n- 图中 Raftstore Pool 和 Apply Pool 这两步通常统称为 Async Write 操作，这个是 TiKV 写入数据的关键流程，也是数据写入分析的重点环节所在。\n\t- Raftstore Pool 和 Apply Pool 处理数据的过程涉及到线程池的调度和处理等，主要消耗 CPU 资源\n\t- rocksdb raft 和 rocksdb kv 由于涉及到数据落盘，主要消耗磁盘 IO 资源\n\t- 数据在不同 TiKV 节点之间进行复制、同步等，主要消耗网络带宽 IO 资源\n\n## 写变慢排查思路\n\n### 常规排查\n\n通常业务的 SQL 变慢后，我们在 TiDB Server 的 Grafana 面板可以看到整体的或者某一百分位的请求延迟会升高，我们可以依次排查物理硬件环境、是否有业务变更操作、数据库运行的情况等，定位到问题后再针对性解决。\n\n![写入慢的常规排查思路](https://img1.pingcap.com/files/2023/09/20230922102657619.png)\n\n如上图是一个写入慢的常规排查思路，在实际工作中对于各项内容的排查可以同时进行，交叉分析，互相配合定位问题所在。\n\n- 遇到问题，先到 Dashboard 看看，对整个集群运行状况有个整体的把握\n\t- 查看集群热力图，关注集群高亮的区域，分析是否有写热点出现，如果有则确认对应的库表、Region 等信息\n\t- 排查慢 SQL 情况，查看集群慢查询结果，分析 SQL 慢查询原因\n\t- 查看 TOP SQL 面板，分析集群的 CPU 消耗与 SQL 关联的情况\n- 物理硬件排查\n\t- 排查客户端与集群之间、集群内部 TiDB 、PD、TiKV 各组件之间的网络问题\n\t- 排查集群的内存、CPU、磁盘 IO 等情况，尤其是混合部署的集群，确认是否存在资源相互竞争、挤兑的场景出现\n\t- 排查操作系统的内核操作是否与官方建议的最佳实践值是否一致，确认 TiDB 集群运行在最优的系统环境内\n- 业务变更\n\t- 确认是否是新上线业务\n\t- 查看集群的 DDL Jobs，确认是否由于在线 DDL 导致的问题，特别是大表加索引的场景，会消耗集群较多的资源，从而干扰集群正常的访问请求\n\n### 全链路排查\n\n对于常规分析无法确认的或者复杂业务的问题，通常排查起来比较棘手，这时候可以分析数据从写入 TiDB Server 到 TiKV Server 、再落盘至 RocksDB 的整个过程，对全部写入链路逐一进行排查，从而确认写入慢所在的节点，定位到原因后再进行优化即可，这一过程大致如下图所示。\n\n![全链路排查](https://img1.pingcap.com/files/2023/09/20230922102650995.png)\n\n毫无疑问，这个是一个兜底的排查思路，适用范围较广，通用性较强，但是排查起来要花费更多的时间和精力，也要求管理员对数据库本身的运行原理有一定的掌握。\n\n- 对于写入慢的全链路分析，我们首先在问题时段从整体上把握延迟情况，再分析 TiDB Server 和 TiKV Server 在对应时段的延迟，确认问题处于计算层还是存储层，接着再深入分析\n\t- 对于 TiDB Server层，主要观察 SQL 的解析优化过程耗时，以及和 PD 进行交互过程的延迟情况\n\t- 对于 TiKV Server 层，重点关注 Scheduler Worker Pool 、Raft log 同步复制与写入、Apply 这几个过程\n\n上面的写入过程的延迟情况，可以从集群的 Grafana 监控面板观察得到，其中 TiKV 是重点所在，其每个阶段写入的流程以及对应在 Grafana 上的延迟监控面板如下。\n\n![延迟监控面板](https://img1.pingcap.com/files/2023/09/20230922102649548.png)\n\n- gRPC duration 或 Scheduler command duration 表示整个写入过程在 TiKV 侧的耗时情况\n\t-  gRPC duration 是请求在 TiKV 端的总耗时。通过对比 TiKV 的 gRPC duration 以及 TiDB 中的 KV duration 可以发现潜在的网络问题。比如 gRPC duration 很短但是 TiDB 的 KV duration 显示很长，说明 TiDB 和 TiKV 之间网络延迟可能很高，或者 TiDB 和 TiKV 之间的网卡带宽被占满\n\t- TiKV Details 下 Scheduler - commit 的 Scheduler command duration 表示执行 commit 命令所需花费的时间，正常情况下，应该小于 1s\n- TiKV Details 下 Scheduler - commit 的 Scheduler latch wait duration表示由于等到锁 latch wait 造成的时间开销，正常情况下应该小于 1s\n- TiKV Details 下 Storage 的 Storage async snapshot duration 表示异步处理 snapshot 所花费的时间，99% 的情况下应该小于 1s\n- TiKV Details 下 Storage 的 Storage async write duration 表示异步写所花费的时间，99% 的情况下应该小于 1s\n- TiKV Details 下 Raft propose 的 Propose wait duration 表示将写入数据请求转为 raft log 的等待时间\n- TiKV Details 下 Raft IO 的 Append log duration 表示 Raft append 日志所花费的时间\n- TiKV Details 下 Raft IO 的 Commit log duration 表示 Raft commit 日志所花费的时间\n- TiKV Details 下 Raft propose 的 Apply wait duration 表示 apply 的等待时间\n- TiKV Details 下 Raft IO 的 Apply log duration 表示 Raft apply 日志所花费的时间\n\n通过对比分析不同阶段的延迟在整体中的占比，通常可以定位到比较慢的环节，然后再针对性优化即可。\n\n官方的 Dashboard 已经帮我们把各个环节汇总了起来，定位到具体的慢写入 SQL 后，可以查看其执行时间，下面是一个例子，里面每个环节的耗时和解释都写得非常清楚，大大降低了问题排查的难度和时间，非常好用：\n\n![示例](https://img1.pingcap.com/files/2023/09/20230922102647319.png)\n\n## 总结\n\n- 常规写入慢的问题，我们可以依次排查物理硬件环境、是否有业务新上线，是否有 DDL 变更操作、执行计划不准、热点问题等情况，通常可以定位到问题，再针对性解决\n- 对于复杂问题则需要对写入过程逐一分析和对比，通常需要反复观察、对比、验证才能找到根本的原因\n\n对于开发人员或 DBA，会解决具体的问题是一项很重要的能力，但定位问题根因所在的能力更难能可贵！\n\n这里想表达的意思，和大家耳熟能详的故事异曲同工：\n\n“老师傅，故障已排除，但就凭这一条线也要 10000$ ？！”\n\n“画这条线要 1$，但知道在哪里画要 9999$！”","date":"2023-09-12","author":"李文杰","fillInMethod":"writeDirectly","customUrl":"tidb-service-write-slow-analysis","file":null,"relatedBlogs":[{"relatedBlog":{"body":"> 本文作者李文杰，网易游戏计费 TiDB 负责人  \n\n## 导读\n\n在使用或运维管理 TiDB 的过程中，大家几乎都遇到过 SQL 变慢的问题，尤其是查询相关的读变慢问题。读变慢的问题大部分情况下都遵循一定的规律，通过经验的积累可以快速的定位和优化，不好排查的问题需要从读 TiDB 的每个过程一一排查和分析处理。  \n\n本文针对读 TiDB 集群的场景，总结业务 SQL 在查询突然变慢时的分析和排查思路，旨在沉淀经验、共享与社区。\n\n## 读原理 \n\n业务 SQL 从客户端发送到 TiDB 集群后，主要经历解析、生成执行计划、执行查询、返回查询结果这几个流程。如下所示是 TiDB 读过程的架构简图：  \n\n![TiDB 读过程的架构简图.png](https://img1.www.pingcap.com/prod/Ti_DB_8fbb8eca45.png)\n  \n来自客户端的每个读取数据的操作，TiDB 也会将其封装为读事务，通常情况下事务在执行的过程分别会与 TiDB Server、TiPD Server 和 TiKV Server 进行交互。  \n\n**TiDB Server** \n\n- 用户提交的业务 SQL 经过 Protocol Layer 进行 SQL 协议转换后，内部 PD Client 向 TiPD Server 申请到一个 TSO，此 TSO 即为读事务的开始时间 txn_start_tso，同时也是该读事务在全局的唯一 ID。  \n- TiDB Server 在解析前会将 SQL 做分类，分为 KV 点查询（唯一键查询，Point Get）和 DistSQL 复杂查询（非点查，Copprocessor ）。  \n  - KV 点查询跳过执行计划优化阶段，直接到查询层，对于在线交易相关的 TP 场景，会大大降低响应延迟。  \n  - 复杂的 SQL 查询会被解析、转为抽象语法树 AST、编译、基于 RBO/CBO 等优化，会生成真正可以执行的计划。最终生成一个个对单个表访问的数据请求。  \n- TiKV Client 模块负责和存储层进行交互，查询请求经过 gRPC 调用，会优先进入 Unified Read Pool 线程池。  \n\n**TiKV Server** \n\n- Unified Read Pool 线程池负责确认查询的数据 Snapshot 和统一调度查询优先级。  \n  - 新来的查询请求其优先级是最高的，落在 L0 队列里。随着查询时间越久，为了保证系统整体吞吐量，慢查询的优先级会不断降低，即会从 L0 调低到 L1、L2 等，随着优先级调低其分配到的 CPU 会减少。  \n  - 也就是说，一个大查询它越慢，它的优先级就会不断调低，优先级不断调低其执行的时间可能会更久。所以，尽可能减少大查询事务。  \n- 查询请求读取 RocksDB 数据  \n  - 先去 LSM Tree 的 MemTable 查找，最新的数据会写在这里，如果命中则返回。  \n  - 如果没找到，继续到 Immutable Memory Table 查找，找到则返回。  \n  - 如果再找不到，则搜查 SST 文件的缓存 Block Cache，找到则返回。  \n  - 如果还没找到，则会开始读取磁盘 SST 文件，会依次搜索 L0 至 L6 各个层级的内容。每一层的文件都会配备一个布隆过滤器。  \n  - 过滤器对一个 Key 如果判断不存在，那么它一定不存在这个 SST 文件内，此时可以跳过这个文件；  \n  - 如果判断在文件内则它可能在可能不在，无法判断准确，此时会直接去查文件内容，由于 SST 文件严格有序，所以在文件内是效率较高的二分查找。  \n- 直到找到数据后，通过 gRPC 调用返回查询结果。  \n\n上面描述的过程，大致就是一个查询请求在 TiDB 集群内部的流转步骤，这也是我们在遇到读慢时的分析步骤。\n\n## 读变慢排查思路  \n\n### 读慢常规分析  \n\n业务的 SQL 变慢后，我们在 TiDB Server 的 Grafana 面板可以看到整体的或者某一百分位的请求延迟会升高，我们根据现象先确认方向性的问题：是整体变慢，还是某个 SQL 变慢。  \n\n![读变慢排查方向.png](https://img1.www.pingcap.com/prod/_37f339835a.png)  \n\n- 是否整体变慢  \n  - 分析各个组件 TiDB、TiKV、TiPD 的响应延迟情况  \n- 整体如果是正常的，继续分析是不是某类 SQL 变慢  \n  - 到 Dashboard 查一查慢查询，看一看集群热力图，分析一下 Top SQL   \n \n根据上面的思路，通常就可以对读变慢的问题有一个整体的把握。  \n\n接着，和写入变慢的分析一样，我们可以依次排查物理硬件环境、是否有业务变更操作等情况，直到定位清楚问题。如下图所示，业务读 SQL 变慢的分析思路可以有下面步骤：  \n\n![读变慢排查常规思路.png](https://img1.www.pingcap.com/prod/_f27d0b193c.png) \n\n- 遇到问题我们应该养成习惯，要先到 Dashboard 看看，对集群运行状况有个整体的把握   \n  - 查看集群热力图，关注集群高亮的区域，分析是否有读热点出现，如果有则确认对应的库表、Region 等信息。[热点问题处理](https://docs.pingcap.com/zh/tidb/stable/troubleshoot-hot-spot-issues#tidb-热点问题处理)  \n  - 排查慢 SQL 情况，查看集群慢查询结果，分析 SQL 慢查询原因  \n  - 查看 TOP SQL 面板，分析集群的 CPU 消耗与 SQL 关联的情况  \n- 物理硬件排查  \n  - 排查客户端与集群之间、集群内部 TiDB 、TiPD、TiKV 各组件之间的网络问题  \n  - 排查集群的内存、CPU、磁盘 IO 等情况，尤其是混合部署的集群，确认是否存在资源相互竞争、挤兑的场景出现  \n  - 排查操作系统的内核操作是否与官方建议的最佳实践值是否一致，确认 TiDB 集群运行在最优的系统环境内  \n- 业务变更  \n  - 确认是否是新上线业务  \n  - 查看集群的 DDL Jobs，确认是否由于在线 DDL 导致的问题，特别是大表加索引的场景，会消耗集群较多的资源，从而干扰集群正常的访问请求  \n\n### 读慢全链路排查  \n\n常规分析思路可以解决绝大部分的问题，对于剩下那些无法确认的或较为复杂业务的问题，这时候可以分析读请求从 TiDB Server 到 TiKV Server 、到读 RocksDB 的整个过程，对全部查询的链路逐一进行排查，从而确认查询慢所在的节点，定位到原因后再进行优化即可，这一过程大致如下图所示。  \n\n![读慢全链路排查.png](https://img1.www.pingcap.com/prod/_5821e64e89.png)  \n\n同样地，这个是一个兜底的排查思路，适用范围较广、通用性较强，但是排查起来要花费更多的时间和精力，也要求管理员对数据库本身的运行原理有一定的掌握。上面的排查步骤还是很复杂的，对用户很不友好。  \n\n但是，目前官方已经推出的 Dashboard 慢查询分析功能，已经帮我们集成和记录了各个环节的延迟，再也不用一个一个去查找 Grafana 面板来确认和分析了，极大地降低排查难度和缩短问题解决时长，是 TiDB 用户的一大福音。  \n\n下面是一个慢查询执行时长分析的例子，可以看到慢查询是因为 TiKV 执行 Coprocessor 任务的累计处理时间比较久，所以导致整个查询较慢， 我们再继续针对性分析和优化 Coprocessor 算子即可。  \n\n![慢查询执行时长分析示意.png](https://img1.www.pingcap.com/prod/_e8905b9ddf.png)\n\n## 总结\n\n- 了解 TiDB 的读过程，有助于我们掌握数据库的底层执行原理，遇到问题时可以快速定位和分析原因，也能引导我们更好地使用数据库，发挥其最好的性能。  \n- TiDB Dashboard 是对用户非常友好的一个官方工具，它使得我们分析慢查询 SQL 变得更轻松和快速，大大降低了问题处理的时间，强烈建议使用。\n- 下面的官方文档，在分析此类问题时推荐优先查看：\n  - [集群读写延迟增加排查](https://docs.pingcap.com/zh/tidb/stable/troubleshoot-cpu-issues)\n  - [热点问题处理](https://docs.pingcap.com/zh/tidb/stable/troubleshoot-hot-spot-issues)  \n  - [定位慢查询]( https://docs.pingcap.com/zh/tidb/stable/identify-slow-queries)  \n  - [分析慢查询]( https://docs.pingcap.com/zh/tidb/stable/analyze-slow-queries)","author":"李文杰","category":4,"customUrl":"tidb-service-read-slow-analysis","fillInMethod":"writeDirectly","id":510,"summary":"本文针对读 TiDB 集群的场景，总结业务 SQL 在查询突然变慢时的分析和排查思路，旨在沉淀经验、共享与社区。","tags":["TiDB"],"title":"最佳实践：TiDB 业务读变慢分析处理"}}]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}