读性能慢-总纲

背景

随着 TiDB 的深入使用,在日常运维当中经常会遇到诸如这样的问题:
为什么我的 TiDB 集群 QPS Duration 升高了?
为什么我的 TiDB 集群,之前很快的语句今天变得执行非常慢了?
为什么我的 TiDB 集群同时出现了大量的 慢 SQL?

诸如此类各种与读请求慢相关的问题。

那么引发这些现象背后的原因是什么?我们要怎么通过 TIDB 的各种监控项与日志排查定位问题?知道了具体问题原因又有什么办法来解这些问题呢?

希望通过这篇文档,能够帮助到您自助的解决这类问题,让 TiDB Cluster 运维起来更加容易。

问题排查思路

TiDB 是一个比较复杂的系统,当出现读请求慢的时候 。有一些问题比较典型,还有一些问题并不常见。通过下面的典型问题排查,往往能解决大部分常见问题。让集群快速恢复到健康状态。还有一部分比较复杂的非典型问题,就需要我们按照读流程一步一步的对集群进行检查。从而找到问题的根源,再考虑如何解决问题

典型问题

通过以下列出的排查路径,来快速 Link 到问题与解决方案

分类 问题
物理环境排查 客户端到 LB\TiDB 网络情况
物理环境排查 服务器是否有网络异常
物理环境排查 系统配置是否符合最佳实践
物理环境排查 硬件资源不足
业务发生变更 业务并发增加\业务逻辑变化
业务发生变更 业务表结构变更
慢语句 获取慢语句
慢语句 统计信息
慢语句 执行计划
慢语句 其他问题
热点问题 判定读热点依据
热点问题 定位具体热点表或索引
热点问题 解决办法

复杂问题排查

TiDB Server 读流程简述

我们将讲述一条 SQL 经过哪些步骤最终构建一个合适的请求发送到 TiKV,这里主要围绕 TiDB server 读流程进行介绍。为了屏蔽细节对于读者的干扰,在不影响正确性的情况下对整个主流程进行简化为如下步骤:

  • 从客户端的 Socket 读取一条 SQL

  • 获取一个 Token

  • 从 PD 获取 TSO (异步获取,此处拿到一个 tsFuture,后续的流程中可以通过 tsFuture 结构拿到真正的 TSO)

  • 使用 Parser 将 SQL parse 为 AST

  • 将 AST compile 为执行计划(此过程包含很多细节,比如 Validator / LogicalPlanOptimizer / PhysicalPlanOptimizer / Executor builder 等,由于都反映在 Compile duration 的监控之中,此处合为一个步骤)

  • 执行上一步得到的执行计划

    • Executor.Open(): 最底层的 Executor 会根据这条 SQL 处理的 Key 范围构建出多个要下发到 TiKV 的请求,并通过 distsql 的 API 将这些请求分发到 TiKV
    • Executor.Next():最底层的 Executor 会将 distsql 返回的数据返回给上层 Executor

    简单说下处理框架:建立链接,TiDB 在收到客户端的查询请求后,进行 MySQL 协议解析和转换,SQL 语法解析,查询计划的制定和优化,查询计划执行等过程。然后切分成一个个以 Range 为单位的子任务, 并行下发到所在的 TIKV 上。经过 TiKV 的处理后返回计算结果,最后将结果返回给客户端。

    由于这一部分涉及的监控非常多且复杂,本小节先从概览到细节对监控进行梳理:

    1. QPS:每秒的查询数量
    2. Duration:SQL 执行的耗时统计
    3. Get Token Duration:建立连接后获取 Token 耗时
    4. Parse Duration:SQL 语句解析耗时统计
    5. Compile Duration:将 SQL AST 编译成执行计划耗时统计
    6. Execution Duration:SQL 语句执行耗时统计

    以上几个监控可以反映一个查询的时间消耗主要是在哪个大模块,比如:

    1. Parse Duration / Compile Duration 是纯 CPU 操作,如果 CPU 负载不高,但是耗时比较长,大部分情况是 insert … values 太多,Compile 高更可能的情况是带了非关联子查询。
    2. Get Token Duration 耗时 比较高说明目前已经在执行的 SQL 达到了 TokenLimiter 的上限,具体情况可能很复杂,比如可能是简单的数量达到了上限,或则内部出现了卡死导致 Token 没有释放。
    3. Execution Duration 包含了 Executor 执行过程中的总耗时,内部涉及的组件比较多,后面将专门对这一部分进行解释。
    4. TSO 获取比较慢,相关的监控有:
      • TSO RPC Duration:pd client 从发送请求到请求返回的耗时,等于网络 roundtrip 耗时 + PD 服务器处理耗时 + Go Runtime 调度耗时(在 CPU 负载较高时候会有所体现)
      • TSO Async Wait:从获取 ts future,到开始 wait ts future 的耗时。反映了 TiDB 内部处理的耗时情况,一般是 parse、compile 以及 auto_increment 的 rebase。向 pd client 发送请求之后,调用者不会卡住,而是得到一个 ts future,只有 wait ts future 的时候,如果 ts future 没有准备好,才会卡住调用者
      • TSO Wait Duration:调用 wait ts future 之后等待 future 返回的耗时

接下来我们就按照对应模块,一步一步的去排查 TiDB Server 层面的读性能问题

TiKV Server 读流程简述

如果在 TiDB Server 层面没有发现问题,那么就需要我们从 TiKV Server 层面继续排查

性能地图 --TiKV Server 部分我们可以看到 整个读流程的过程


为了便于理解 我们将它再进一步细化。 如图:

让我们再一次具体看看查询语句在 TiDB Cluster 中是如何处理的:

  1. TiDB 收到查询语句,对语句进行分析,计算出物理执行计划,组织成发送给 TiKV 的 Coprocessor/kv_get/kv_batch_get 请求。
  2. TiDB 根据上面的请求的类型,并根据数据的分布,将请求分发到所有相关 TiKV 上对应的线程池中。
  3. TiKV 在收到请求后,先构建出一个 snapshot ,然后再采用不同的请求算子对数据进行搜索、过滤、聚合,然后返回给 TiDB
  4. TiDB 在收到所有数据的返回结果后,进行二次聚合,并将最终结果计算出来,返回给客户端。

PS.关于 Coprocessor/kv_get/kv_batch_get ,下面会做一些简单解释:

  • TiKV 读取数据并计算的模块,我们定义为 Coprocessor,该概念灵感来自于 HBase, 目前在 TiDB 中的实现类似于 HBase 中的 Coprocessor 的 Endpoint 部分,也可类比 MySQL 存储过程。
  • kv_get/kv_batch_get 我们可以简单的理解为处理执行计划中显示为 Point_Get 的请求,即根据主键进行的点查或批量查询

再一次、再一次、再一次,确认服务器的负载情况

在开始细分析,TIKV 哪个环节导致读请求变慢之前,建议首先查看当前集群服务器的负载情况,可以在 Overview 监控面板中,可以看到当前各节点服务器的 Load、CPU 使用情况、磁盘 IO 使用情况、以及网卡流量使用情况,如果上面各指标的使用已经比较繁忙,甚至达到饱和,建议先着重查看导致上述问题的原因,比如:

  • 出现较多慢 SQL
  • 其他外部程序占用
  • 业务本身繁忙(考虑扩容)
  • 以及其他典型问题可能导致的问题

接下来我们就按照对应模块,一步一步的去排查 TiKV Server 层面的读性能问题

TiKV Server 读流程分析

1赞

这个系列的文章很吊,学到了:tulip:

如果有不清楚的地方,也请提问,我们会进行相关文章的在线迭代与解答
感谢支持