背景:

        笔者参与一个Spark项目,经常要与Spark、Yarn、Livy以及它们的Web界面打交道,来查看错误日志、分析性能瓶颈等。但最初总是分不清楚三者的区别,也不理解每一个UI侧重展示的信息,以及如何利用这些信息等。因此本文结合笔者自身的经验在此进行一些总结。

项目技术选型:

  • 计算引擎采用Spark
  • 存储及资源管理分别是HDFS和Yarn
  • 利用Livy将任务提交到Spark集群
  • Spark集群运行模式:Yarn;部署模式:Cluster
虚拟机名称IP核心数(V)内存(GB)系统盘(GB)操作系统
spark-master172.20.70.154163250CentOS 7.6
spark-slave1172.20.70.15583250CentOS 7.6
spark-slave2172.20.70.15683250CentOS 7.6
spark-slave3172.20.70.163163250CentOS 7.6
spark-slave4172.20.70.164163250CentOS 7.6

一、总体把握

        Yarn是Hadoop 2.x提出的分布式通用资源管理系统,负责CPU、内存等集群资源的管理。说它“通用”,是因为虽然它从Hadoop生态发展出来,但它能够支持更广泛的计算架构(MapReduce / Spark / Flink等)和存储系统(HDFS / Hbase / Hyperbase等)。

        Spark从Hadoop MapReduce发展而来,但不同于MapReduce的是Job中间输出和结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的map reduce的算法。

        Livy用户可以以REST请求的方式通过Livy启动一个新的Spark集群,提交Spark作业到远端的Spark集群上执行。

二、Yarn Web UI

参考课程:

Yarn 基本架构

三种角色:ResourceManager(Master)、NodeManager(Slave)、ApplicationMaster

具体流程:Client提交一个作业(这里是Spark作业),ResourceManager首先分配一部分资源到一个NodeManager节点的一个Container中,然后在Container中会运行作业自己的管理进程ApplicationMaster,它将作业(job)解析成不同的task,向ResourceManager申请所需的更多资源,之后ResourceManager启动更多NodeManager的Container,然后Task就能被分发到多个Container执行,执行过程中Task向ApplicationMaster汇报,ApplicationMaster也会对其它Task进行监管,执行完毕后ApplicationMaster负责收集数据,并向ResourceManager请求释放Task所占Container的资源。

在上述过程中,ResourceManager仅负责资源管理,任务调度交由ApplicationMaster进行。

Yarn Web UI 在主节点spark-master的8088端口查看:

左上角的图标是“Hadoop",因为Yarn是Hadoop的资源管理组件。左侧是目录,About / Nodes展示集群整体情况和各节点的信息;Scheduler是Yarn资源调度的策略(FIFO、Capacity、Fair等);Applications就是提交的各个作业,还可以点击细分类,例如RUNNING,查看当前处于运行状态的作业。

(About)

(Nodes,可以看到集群中包含四个Node Manager)

接下来举几个具体作业的例子:

(1)提交的作业编译出错,Yarn UI 对于该条作业状态显示FAIED。

可以点击application链接,进入查看具体的错误信息。

还可以在spark-master服务器输入如下命令查看更详细的日志信息(applicationId替换成自己实际的作业Id):

yarn logs -applicationId application_1755842062391_0198

(2)作业顺利提交且编译成功,FinalStatus显示SUCCEEDED,但作业是否按照预期成功执行,还需要进一步查看Spark Web UI。

进入详情页可以看到Node一栏中显示driver程序运行在节点spark-slave2上。

(3)作业顺利提交,但State是RUNNING,FinalStage一直是Undefined。

查看详情页,YarnApplicationState显示任务还在等待AM container创建,当前资源不足。同时观察到,前面有个任务一直在Running,很明显资源被占用了。

三种解决方案:(1)可以等待前面的任务完成;(2)如果前面的任务不再需要继续,可以手动点击左上角的Kill;(3)可以对资源调度策略进行修改。

三、Spark Web UI

        这是集群中spark应用程序的一般执行框架,主要由SparkContext(spark上下文)、ClusterManager(资源管理器)和Executor(单个节点的执行进程)三部分组成。在Spark On Yarn (cluster) 模式下,ClusterManager是Yarn,负责整个集群的统一资源管理;executor是应用执行的主要进程(独立的JVM进程),内部含有多个task线程以及内存空间;driver程序会和ClusterMananer通信,并分配task到executor上执行。

        联想Yarn架构中的三种角色,driver和ApplicationMaster同属一个进程,并且driver可能在任意一台NodeManager。一个Yarn的container只能有一个Spark Executor,一个worker节点可以有多个executor。

参考资料:

大佬教你透视spark任务日志:Spark UI 一级入口,问题定位排查

Spark Web UI 4.0.0

        在运行Spark Application的时候,Spark会提供一个WEB UI列出应用程序的运行时信息,但该WEBUI随着Application的完成(成功/失败)而关闭。Spark history Server通过配置可以在Application执行的过程中记录下日志事件信息,在Application执行结束后Web UI能重新渲染展示。
在spark安装目录下找到sbin目录,进入后执行start-history-server.sh,默认端口18080。

只要提交的是Spark作业,Yarn UI中的每一个FinalStatus为SUCCEEDED的任务(application)在Spark UI一定会有对应的一条。点击进去可以查看到详细的Spark作业流程。

Spark实际执行流程:用户代码 → 逻辑处理流程 → 物理执行计划

其中,逻辑处理流程只是表示输入输出中间数据以及它们之间的依赖关系,并不涉及具体的计算任务;物理执行计划的生成首先根据action操作顺序将应用划分为作业(job),然后根据每个job的逻辑处理流程中的ShuffleDependency依赖关系,将job划分为执行阶段(stage)。最后在每个stage中,根据最后生成的RDD的分区个数生成多个计算任务(task),同一个stage中的task可以并行执行。

Spark会提前启动JVM Executor进程,需要运行task时在其中起线程(这里和Hadoop的MapReduce不一样,Hadoop是在task运行的时候启动JVM进程)。这里对Spark executor和Yarn container这两个概念的关系做一个澄清,Executor是 Spark 应用程序在集群中运行的进程,它的数量和资源由Yarn动态分配;Container 是Yarn分配给 Executor 的运行环境,它是一个隔离的执行环境,能够确保 Executor 之间的资源隔离。

点击application链接后进入该任务的详情页,这一页面对于分析Spark性能瓶颈具有非常大的帮助。一级页面中Jobs、Stages按照物理执行计划的划分供用户查看任务各阶段信息;Storage显示任务中持久化的RDD和DataFrame(若存在);Environment列出JVM、Spark及系统属性等各类环境与配置参数值;Executors展示任务执行过程中各executor进程资源使用情况、Shuffle信息等;SQL仅在执行Spark SQL查询时出现,展示查询的持续时间、关联作业等信息。

对于分析比较有帮助的几处信息:

(1)Environment页面System Properties中有一项内容sum.java.command,在这里可以看到启动命令。

(2)在Jobs页面查看事件时间线

(3)在Jobs页面进入具体的某个Job,或直接进入Stages页面,点击各stage右侧的details可以看到相关代码详情信息,帮助定位。如果是正在运行的stage(active stages),details的旁边还会提供kill链接,可以对stage进行kill。

(4)有时候性能比较差,可以通过查看以下三处地方判断是否出现“数据倾斜”。

        进入某个具体Stage后,可以查看Summary Metrics统计信息,观察执行时间的中位数(或75分位数)与Max是否差别过大,差距过大说明存在数据倾斜;进一步查看Event Timeline,查看各executor中各task的运行时间线,是否均衡,若各别executor或各别task时间线远长于其它,说明存在数据倾斜。

        还可以直接到Executors界面查看executor的总览信息,观察各executor中运行的task线程数量是否均衡、时间是否均衡。

(5)Executor界面可以看到driver程序被提交到了哪个节点,这里可以看到是spark-slave2。

四、Livy UI

参考资料:Livy Session的创建(视频一般,可作初学参考)

Livy和Spark一样在Apache旗下,是用于Rest远程调用Spark集群的一个服务。Livy将每一个启动的Spark集群称之为一个会话(session),一个会话是由一个完整的Spark集群所构成的,并且通过RPC协议在Spark集群和Livy服务端之间进行通信。session 最大特点是可以共享 SparkContext,让用户提交的多个代码片段都能跑在一个 SparkContext 上,加速任务的启动速度。

停止和启动服务:livy-server stop;  livy-server start

通过使用livy-session,相当于通过rest执行spark-shell,处理交互式请求;通过使用livy-batch,相当于通过rest执行spark-submit,处理非交互式请求。

Session创建后等待其状态由starting变成idle,然后提交job,执行时session状态变成busy,执行完毕后又会变成idle。

通过livy启动session后,在Yarn界面可以看到对应的正在运行的名为livy-session的任务,这两项任务会长期存在(状态一直是RUNNING),等待用户通过livy继续向session提交作业。

Logs列有两个链接,一个是session,一个是drvier。session日志显示的是提交spark工作时client打印的日志;drvier日志跳转到yarn日志,显示的是driver运行输入的日志。

(DeepSeek生成 ⬆)

livy里面管理的session代表的就是和某一个客户端的链接,和yarn里面的app并不完全一对一的关联,也不和spark context完全一对一的关联,虽然大部分情况下都是一对一。

点击Session Id链接,可以查看到session中多次的Execution Code以及对应的Output信息,还有开始、结束时间。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐