6.8.2 查询性能分析¶
在 Doris 执行查询时,当碰到查询性能未达预期时,建议做进一步分析情况。本文将全面阐述如何在 Doris 中对查询进行性能分析。
在 Doris 中,由于 Profile 收集会产生一定的开销,因此默认情况下它是关闭的。若要进行查询性能分析,我们首先需要将其开启,具体操作为在 MySQL Client 中执行以下命令:
| SQL | |
|---|---|
1 | |
1 QueryID 排查慢查询¶
查询性能问题分析的首要步骤是获取待分析查询的 QueryID 。这个 QueryID 可以从 fe/log/fe.audit.log 日志文件中找到。
以 TPC-H 中的某条特定查询为例,通过查看日志信息,我们可以发现该查询的 QueryID 为 QueryId=704185c15570441b-98ad0634c88584f0 。
| SQL | |
|---|---|
1 | |
2 Profile 分析查询性能¶
在获取 QueryID 后,可以通过访问对应 FE 的 WebUI 来检索 Profile 文本。例如,通过访问链接 http://{fe_ip}:{http_port}/QueryProfile/704185c15570441b-98ad0634c88584f0 ,即可获取到相应的 Profile 信息,查看更多详细信息,可以下载 profile_704185c15570441b-98ad0634c88584f0.txt 文件。
2.1 Profile 文件结构¶
Profile 文件中包含以下几个主要的部分:
-
查询基本信息:包括
ID,时间,数据库等 -
SQL语句以及执行计划。 -
FE的耗时(Plan Time,Schedule Time等)。 -
BE在执行过程中各个Operator的执行耗时(包括Merged Profile、Execution Profile、以及Execution Profile中的每个PipelineTask)。
在慢查询中,通常耗时主要集中在 BE 的执行过程,接下来将主要介绍这部分的分析过程。
2.2 通过 Merged Profile 进行 BE 执行分析¶
为了帮助用户更准确地分析性能瓶颈, Doris 提供了各个 Operator 聚合后的 Profile 结果。
以 EXCHANGE_OPERATOR(id=4) 为例:
| SQL | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 | |
Merged Profile 对每个 Operator 的核心指标进行了合并。核心指标及其含义如下:
| 指标名称 | 指标含义 |
|---|---|
| BlocksProduced | 产生的 Data Block 数量 |
| CloseTime | Operator 在 Close 阶段的耗时 |
| ExecTime | Operator 在各个阶段执行的总耗时 |
| InitTime | Operator 在 Init 阶段的耗时 |
| MemoryUsage | Operator 在执行阶段的内存用量 |
| OpenTime | Operator 在 Open 阶段的耗时 |
| ProjectionTime | Operator 在进行 Projection 的耗时 |
| RowsProduced | Operator 返回的行数 |
| WaitForDependencyTime | Operator 等待自身执行条件依赖的时间 |
在 Doris 中,每个 Operator 根据用户设置的并发数并发执行。因此, Merged Profile 对每个执行并发的每个指标都计算出了 Max 、 Avg 和 Min 的值。
其中, WaitForDependencyTime 指标在不同 Operator 对应有不同的值,因为每个 Operator 执行的条件依赖不同。例如,在这个 EXCHANGE_OPERATOR 的例子中,条件依赖是有数据被上游的算子通过 RPC 发送过来。因此,这里的 WaitForDependencyTime 实际上就是在等待上游算子发送数据的时间。
2.3 通过 Execution Profile 进行 BE 执行分析¶
区别于 Merged Profile , Execution Profile 展示的是具体的某个并发中的详细指标。
还是以 EXCHANGE_OPERATOR(id=4) 为例:
| SQL | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Tip
在该 Profile 中, LocalBytesReceived 是 Exchange Operator 特有的一个指标,其他 Operator 中并不存在,因此它也没有被包含在 Merged Profile 中。
2.4 PipelineTask 执行时间分析¶
在 Doris 中,一个 PipelineTask 由多个 Operator 组成。当分析一个 PipelineTask 的执行耗时时,需要重点关注以下几个方面:
-
ExecuteTime:表示整个PipelineTask的实际执行时间,它大约等于该Task中所有Operator的ExecTime之和。 -
WaitWorkerTime:表示Task等待执行Worker的时间。当Task处于runnable状态时,它需要等待一个空闲的Worker来执行,该耗时主要取决于集群的负载情况。 -
等待执行依赖的时间:一个
Task可以执行的依赖条件是每个Operator的Dependency全部满足执行条件,而Task等待执行依赖的时间就是将这些依赖的等待时间相加。
以上述例子中的其中一个 Task 为例:
| SQL | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
该 task 包含了 DATA_STREAM_SINK_OPERATOR 和 AGGREGATION_OPERATOR 两个 Operator 。其中:
-
DATA_STREAM_SINK_OPERATOR有两个依赖,分别是WaitForBroadcastBuffer和WaitForRpcBufferQueue -
AGGREGATION_OPERATOR有一个依赖,为AGGREGATION_OPERATOR_DEPENDENCY。
因此,当前 Task 的耗时分布如下:
-
ExecuteTime(执行总时间):1.656ms(约等于两个Operator的ExecTime总和) -
WaitWorkerTime(等待Worker的时间):63.868us(说明当前集群负载不高,Task就绪以后立即就有Worker来执行) -
等待执行依赖的时间:
10.495ms(WaitForBroadcastBuffer + WaitForRpcBufferQueue + WaitForDependency[AGGREGATION_OPERATOR_DEPENDENCY]Time)即当前task的所有Dependency相加得到的总的等待时间。
3 性能问题通用排查思路¶
在 Doris 执行查询的过程中,通常可以依据以下四个步骤来排查性能问题:
3.1 定位算子执行性能问题¶
算子执行缓慢是日常生产环境中较为常见的一类问题。在定位过程中,可以根据 Merged Profile 中的 Plan Tree ,梳理出每个 Operator 的 ExecTime 和 WaitForDependencyTime 。
-
若
ExecTime较慢,则表明当前算子存在性能问题,这可能是算子本身执行性能不佳,也可能是执行规划的Plan不够优化所导致的。 -
若
ExecTime很快,但WaitForDependencyTime很长,则说明性能瓶颈不在当前算子,需沿着Plan Tree继续查找其子节点。
3.2 定位数据倾斜问题¶
在定位算子性能问题的过程中,若发现某个算子的 ExecTime 的最小值( Min )和最大值( Max )相差悬殊,则需观察该算子的数据量( RowsProduced )是否同样存在显著差异。若是,则说明发生了数据倾斜。
3.3 定位 RPC 延迟过大的问题¶
当遍历完整个 Plan Tree 之后,若未能找到任何执行缓慢的算子,接下来需排查是否因 RPC 延迟过大而导致的性能问题。
在此过程中,需找到 Execution Profile 中的每个 DATA_STREAM_SINK_OPERATOR ,并检查其中的 RpcMaxTime 是否存在异常值。该指标指明了 RPC 过程中耗时最长的一次调用,若其值过大,则代表 RPC 延迟较高,可能是网络问题所致。
3.4 定位集群负载过高导致的性能问题¶
在 Doris 的执行引擎中,执行线程数量是固定的。因此,当集群负载很高时,每个 Task 需等待空闲的执行 Worker 来执行。可以通过 Execution Profile 中的每个 PipelineTask 下,查看 WaitWorkerTime 指标来获取等待时间的信息,以进一步判断。