二、Spark UI 一级入口
启动Spark UI后,默认会进入当前作业的Jobs页面,这里记录了数据移动、读取等关键动作。除此之外,导航栏还提供了其他几个核心的一级入口,用于展示作业运行时的各类属性与性能指标,主要包括:Stages、Storage、Environment、Executors以及SQL。
这些页面共同构成了诊断Spark应用的第一站。为了快速定位问题,我们通常需要一套系统的查看方法。下图汇总了在各个一级页面中应重点关注的信息,可视为一份Spark任务诊断的“快速查阅清单”:

接下来,我们将从评估任务整体计算负载开始,由简入繁地介绍各个入口的功能与作用。首先,让我们从 Executors 页面入手。
Executors
Executors页面主要包含两部分:Summary 和 Executors。
- Summary 是所有Executor度量指标的加和,提供了集群级别的总体视图。
- Executors 则详细列出了每一个Executor的信息,粒度更细,便于分析单个节点的运行状况。
页面示例如下:

为了帮助您更好地理解每个Executor节点的运行状态,下表详细解释了Spark UI在Executors页面提供的各项关键Metrics:

通过观察不同Executor的状态和指标,我们可以快速判断是否存在负载不均衡的情况,例如某个Executor处理了远多于其他节点的数据(Total Shuffle Read/Write 异常高),这往往是 数据倾斜 的直接证据。因此,Executors页面是监控资源使用和诊断分布式计算问题的重要窗口。
Environment
顾名思义,Environment页面主要展示任务运行时的配置信息。它系统地分为五大类环境信息:

在日常的 性能调优 和问题排查中,我们最常关注的是 Spark Properties。通过检查这里的配置项,可以验证spark.sql.adaptive.enabled、spark.executor.memory等关键参数是否已按预期生效,从而为后续的参数调整提供准确依据。
Storage
Spark UI的Storage页面是监控和管理缓存数据(Persisted/Cached Data)的核心窗口。它直观地展示了哪些RDD或DataFrame被缓存、存储级别是什么、占用了多少内存或磁盘资源,是优化内存使用、避免OOM(Out of Memory)错误的关键工具。
页面会展示类似下图的缓存信息:

其中,Cached Partitions 与 Fraction Cached 分别表示已成功缓存的分区数量及其占总分区数的比例。如果 Fraction Cached 未达到100%,则意味着数据集未能完全缓存在内存中。结合Spark的内存管理模型可知,此时可能会出现数据在内存和磁盘间换入换出的情况,这显性地表明参与计算的数据量较大,执行内存(Execution Memory)可能会挤占存储内存(Storage Memory)。而 Size in Memory 与 Size on Disk 则直接展示了数据集在内存和磁盘上的占用大小。
SQL
Spark UI的SQL页面是专门为Spark SQL / DataFrame作业设计的核心监控与优化入口。它将逻辑执行计划、物理执行过程、性能瓶颈和数据流动以可视化的方式呈现,是诊断慢查询、验证优化策略(如AQE)的“驾驶舱”。
该页面会列出所有正在运行或已完成的SQL查询,如下图所示:

Stages
Stages界面是进行Spark作业性能调优和故障诊断的核心入口。它以Stage(阶段)为粒度,展示作业执行的详细细节,帮助你精准定位慢任务、数据倾斜、资源瓶颈等问题。
页面会展示所有作业的阶段列表:

为了有效分析Stage,我们需要理解其关键指标。下表对Stage列表中的主要Metrics进行了解释:

Jobs
Jobs界面是整个Spark应用监控体系的顶层入口。它以Job(作业)为单位,提供全局视角的执行概览,帮助你快速判断应用整体健康状况、识别失败作业、以及定位性能瓶颈的起点。
页面会列出所有作业:

同样,理解Jobs页面的指标对于快速诊断至关重要:

小结
至此,我们对Spark UI导航栏中的各个一级页面进行了初步解析。整体来看,这些页面可以分为两类:
- “详情型”页面:包括 Executors、Environment 和 Storage。 它们直接展示集群的系统级状态,如计算资源负载分布、运行时环境配置、缓存数据详情等。开发者无需额外跳转,即可快速获取关键的底层信息。
- “概览 + 下钻型”页面:包括 SQL、Jobs 和 Stages。 它们首先以列表形式提供作业或查询的高层汇总视图。若需深入分析执行计划、任务分布、性能瓶颈等细节,则需要点击进入对应的二级详情页进行下钻探查。
这种分层设计既支持快速概览,又保留了深度诊断的能力,为开发者提供了从宏观到微观的完整观测路径。
三、Spark UI 二级入口
二级入口指的是需要通过点击一级页面中的超链接(如某个SQL查询、Job ID或Stage ID)才能进入的详情页面。对于 SQL、Jobs 和 Stages 这三个入口而言,其对应的二级页面包含了极为丰富的诊断信息,基本构成了Spark应用的“健康体检报告”核心。
接下来,我们将按照 SQL → Stages 的逻辑顺序,深入这两个核心的二级详情页,系统性地剖析全局DAG执行结构以及各计算阶段的资源使用与运行细节。
SQL详情页
从SQL页面点击查询描述(例如下图中WITH...开头的部分),即可进入该查询的详细执行计划页面:

在数据分析中,大部分操作可归纳为过滤、分组、聚合、关联和排序。在执行计划图中:
- Exchange:代表Shuffle操作,涉及数据跨节点网络传输。
- Sort:代表排序操作。
- Aggregate:代表数据聚合操作。
这三类操作是消耗硬件资源(CPU、内存、磁盘I/O、网络I/O)的主要环节。Spark UI为它们提供了丰富的细粒度指标(Metrics)。下面我们逐一解析。
Exchange (Shuffle)
点击执行计划图中的Exchange节点,可以看到详细的Shuffle指标:

针对每个Exchange操作,Spark UI提供了覆盖Shuffle全生命周期的细致指标。为了便于理解,将其整理如下:

Sort
对于排序操作,关键指标如下图所示:

其中,Peak memory total(峰值内存消耗)和 Spill size total(溢出到磁盘的数据总量)是两个至关重要的指标。如果Spill size total很大,说明排序过程中内存不足,发生了磁盘溢出,这会严重拖慢性能。这两个数值直接指导我们调整spark.executor.memory、spark.memory.fraction等内存相关参数,以确保Execution Memory区域充足。
Aggregate
对于聚合操作,Spark UI同样记录了磁盘溢出与峰值内存消耗:

Spill size 和 Peak memory total 为评估聚合操作的内存需求、预防OOM提供了直接依据。
Stages详情页
在所有二级入口中,Stage详情页的信息量最为庞大。它主要包含3大类信息:Stage DAG、Event Timeline 和 Task Metrics。其中,Task Metrics又分为“Summary”汇总统计和“Tasks”详细列表。
进入Stage详情页后,首先看到的是概览:

Stage DAG
Stage DAG展示了当前阶段内的计算链,相对简单,因为它在整个作业DAG中只是一个片段。示例如下:

Event Timeline
Event Timeline(事件时间线)以甘特图形式展示了该阶段所有Task在调度与执行过程中,各个环节的时间开销。每个横条代表一个Task,由不同颜色的区间组成,代表不同环节的计算时间。

不同颜色对应的环节如下表所示:

如何分析并优化?
理想情况下,Task时间条带应以绿色(Executor Computing Time,实际计算时间)为主。如果出现其他颜色占比过高,则表明存在系统开销瓶颈。
- 针对调度延迟高(深蓝色
Scheduler Delay 大): 这可能意味着任务等待资源的时间过长。可以尝试调整资源配置,一个经验公式是关注 数据量/分区数 与 Executor内存/CPU核数 的比例,使其匹配,避免单个任务过重或资源闲置。
- 针对Shuffle负载重(黄色
Shuffle Write和橙色Shuffle Read时间长): 这表明跨节点数据交换成为瓶颈。优化思路包括:
- 检查是否可使用Broadcast Join替代Shuffle Hash Join。
- 调整
spark.sql.shuffle.partitions 参数,避免产生过多或过少的分区。
- 利用AQE(自适应查询执行)特性,如开启
spark.sql.adaptive.enabled 来自动合并小文件。
Task Metrics
Task Metrics是Spark在每个Task执行完毕后收集的细粒度性能数据,是性能调优的基石。分析时,通常先看Summary Metrics把握整体,再深入Tasks列表定位具体问题。
Summary Metrics
Summary是对该阶段所有Task指标的统计摘要(最小值、中位数、最大值等),能快速反映整体表现。

将其中的关键指标整理如下:

其中,Spill (Memory) 和 Spill (Disk) 值得特别关注。它们分别表示Task因内存不足而溢出到磁盘的数据在内存中的原始大小和落盘后的大小。计算两者的比值(Spill (Memory) / Spill (Disk)),可以得到一个近似的“数据膨胀系数”。这个系数有助于我们评估数据在内存中的真实占用,从而更精确地配置Executor内存,预防OOM。
Tasks
Tasks列表逐行展示了每个Task的详细指标,其字段含义与Summary Metrics中的一致。

此视图新增了少数几个指标,其中最有用的是 Locality Level(本地性级别)。它表示Task在哪个数据本地性级别上得以执行(如PROCESS_LOCAL-进程本地,NODE_LOCAL-节点本地,RACK_LOCAL-机架本地,ANY-任意)。这体现了Spark“移动计算而非数据”的设计哲学。本地性级别越高,网络传输开销越小,任务执行效率通常越高。
Tasks列表的主要价值在于定位异常个体,例如:
- 执行时间(
Duration)远超中位数的Task。
- Shuffle读取数据量(
Shuffle Read Size)异常大的Task(可能承载了倾斜数据)。
- 垃圾回收时间(
GC Time)过长的Task。
通过对比异常Task与整体统计的偏差,可以快速 pinpoint 性能瓶颈。
四、实战环节
理论结合实践,下面通过两个典型场景演示如何利用Spark UI进行问题定位和 参数调整。
案例一:Scan表慢与内存问题
在Stages页面,我们首先按Duration降序排列,找到运行时间最长的Stage进行分析。

进入该Stage的详情页,查看Task的Summary Metrics:

同时,在Tasks列表中观察失败或特别慢的Task:

问题分析:
- Task数据量过小:从Summary Metrics看,每个Task处理的输入数据量(
Input Size)仅约25MB,而通常一个Task处理128-256MB数据较为合理。这表明源表可能存在大量小文件,导致生成的Task数量过多。
- 调度延迟高:失败Task的日志显示
Scheduler Delay(调度延迟)过长。这是因为Task总数过多,而集群并发执行能力有限,导致大量Task在队列中等待。
解决方案:
-
调整输入切片大小:通过设置表级别的参数,增大每个Task读取的数据量,从而减少Task总数。例如,在阿里云MaxCompute(ODPS)环境中:
set spark.sql.odps.split.size.your_project.your_table=512MB;
调整后,该Stage运行时间缩短了约20分钟。
-
调整Executor资源:减少spark.executor.cores(隐性增大每个Task可用的内存)或直接增大spark.executor.memory(显性增大内存),以应对因Task数据量增大可能带来的内存压力。当Task出现磁盘溢出(Spill)时,此法效果更显著。
总结: 当Scan表因小文件多导致Task数量爆炸时,可通过调整输入切片大小来合并任务;同时关注Spill指标,决定是否需要增加内存。
案例二:Shuffle后并行度不足
同样,在Stages页面找到Shuffle后耗时最长的Stage。

进入Stage详情,通过DAG图或Exchange节点信息,发现Shuffle后的分区数很少,导致下游计算并行度跟不上。

问题分析: Shuffle阶段产生的输出分区数过少,导致下游Stage的并行度不足,无法利用好集群资源。
解决方案:
调整Shuffle相关参数,增加并行度:
- 调整AQE建议的分区大小:
spark.sql.adaptive.advisoryPartitionSizeInBytes(默认64MB),减小此值会促使AQE生成更多分区。
- 提高初始Shuffle分区数:
spark.sql.adaptive.coalescePartitions.initialPartitionNum(默认与spark.sql.shuffle.partitions相同,通常为200)。
示例参数设置:
"spark.sql.adaptive.advisoryPartitionSizeInBytes": "64MB",
"spark.sql.adaptive.coalescePartitions.initialPartitionNum": "1000"
如果发现调整后分区数仍无变化,可能是因为某些限制(如minPartitionSize)阻止了进一步切分,可能需要同步调整这些下限值。
五、总结
通过Spark UI进行性能优化或问题定位,始终绕不开 内存 与 并行度 这两个核心维度。二者相互影响、相互制约:
- 并行度 决定了“有多少个Task同时运行”。
- 内存 决定了“每个Task能分到多少资源”。

资源配置的经验性思考:
假设一个Stage的并行度(Task总数)为P,集群配置为:每个Executor内存为M,核数为C,最大Executor数量为N。
那么:
- 集群最大并发Task数 ≈ N * C。
- 该Stage需要分批执行的轮次 ≈ P / (N * C)。
- 每个Task平均可分得的内存 ≈ M / C。
一个经验法则是,每Core分配4-8GB内存通常是一个合理的范围,而总Task数(P)约为最大并发Task数(NC)的2-3倍时,资源利用比较均衡。例如,如果P=5000,NC=1000(即需要5批执行),且M/C=3GB,可能略小。可以尝试将配置优化为executor.memory=24g, executor.cores=4(此时M/C=6GB),以提升单Task资源并减少执行轮次。
理想的Spark作业状态是:Task负载均衡、无磁盘溢出(Spill)、CPU利用率高、内存充足且无频繁GC。 Spark UI正是帮助我们洞察现状、衡量差距、并最终实现这一目标的强大工具。
希望这篇深入的解析能帮助您在 大数据 处理任务中更好地驾驭Spark UI,成为性能调优的专家。如果您在实践中有更多心得或疑问,欢迎到技术社区进行 互动交流。