Spark浅析

Spark应用程序

Spark应用程序由一个驱动器进程和一组执行器进程组成。驱动进程运行main()函数,位于集群中的一个节点上,它负责三件事:维护Spark应用程序的相关信息;回应用户的程序或输入;分析任务并分发给若干执行器进行处理。驱动器是必须的,它是Spark应用程序的核心,它在应用程序执行的整个生命周期中维护着所有相关信息。

执行器负责执行驱动器分配给它的实际计算工作,这意味着每个执行器只负责两件事:执行由驱动器分配给它的代码,并将该执行器的计算状态报告给运行驱动器的节点。

Spark API的多语言支持

Scala:Spark主要用Scala编写

Java:可以用Java编写Spark代码

Python:Python几乎支持所有Scala支持的结构

SQL:Spark支持ANSI SQL2003标准的一个子集

R:Spark有两个常用的R库:一个作为Spark核心的一部分(SparkR),另一个是R语言开源社区维护的包(sparklyr)

启动Spark

当以交互方式启动Spark时,相当于隐式地创建了一个SparkSession来管理Spark应用程序,当不是通过交互模式而是通过独立应用程序启动Spark时,必须在应用程序代码中显式地创建SparkSession对象。

DataFrame

DataFrame是最常见的结构化API,简单来说,它是包含行和列的数据表,说明这些列和列类型的一些规则被称为模式(schema),可以将DataFrame想象为具有多个命名列的电子表格,但是我们熟悉的电子表格和Spark DataFrame是不同的,电子表格位于一台计算机上,而Spark DataFrame可以跨越数千台计算机。

Spark有几个核心抽象:Dataset,DataFrame,SQL表和RDD,这些不同的抽象都表示分布式数据集合,其中最简单和最有效的是DataFrame,它支持所有语言

数据分区

为了让多个执行器并行地工作,Spark将数据分解成多个数据块,每个数据块叫做一个分区。分区是位于集群中的一台物理机上的多行数据的集合,DataFrame的分区也说明了在执行过程中数据在集群中的物理分布。如果只有一个分区,即使拥有数千个执行器,Spark也只有一个执行器在处理数据。类似地,如果有多个分区,但只有一个执行器,那么Spark仍然只有一个执行器在处理数据,就是因为只有一个计算资源单位。

转换操作

转换操作是使用Spark表达业务逻辑的核心,有两类转换操作:第一类是指定窄依赖关系的转换操作,第二类是指定宽依赖关系的转换操作

具有窄依赖关系的转换操作(我们称之为窄转换)是每个输入分区仅决定一个输出分区的转换

具有宽依赖关系的转换是每个输入分区决定了多个输出分区,这种宽依赖关系的转换经常被称为洗牌(shuffle)操作,它会在整个集群中执行互相交换分区数据的功能。如果是窄转换,Spark将自动执行流水线处理,这意味着如果我们在DataFrame上指定了多个过滤操作,它们将全部在内存中执行,而属于宽转换的shuffle操作不是这样,当我们执行shuffle操作时,Spark将结果写入磁盘。

惰性评估

惰性评估的意思就是等到绝对需要时才执行计算。在Spark中,当用户表达一些对数据的操作时,不是立即修改数据,而是建立一个作用到原始数据的转换计划。Spark首先会将这个计划编译为可以在集群中高效运行的流水线式的物理执行计划,然后等待,直到最后时刻才开始执行代码。这会带来很多好处,因为Spark可以优化整个从输入端到输出端的数据流。一个很好的例子就是DataFrame的谓词下推,假设我们构建一个含有多个转换操作的Spark作业,并在最后指定了一个过滤操作,假设这个过滤操作只需要数据源中的某一行数据,则最有效的方法是在最开始仅访问我们需要的单个记录,Spark会通过自动下推这个过滤操作来优化整个物理执行计划。

动作操作

转换操作使我们能够建立逻辑转换计划,为了触发计算,我们需要运行一个动作操作(action),一个动作指示Spark在一系列转换操作后计算一个结果,最简单的动作操作是count,它计算一个DataFrame中的记录总数,count不是唯一的动作,有三类动作:

  1. 在控制台中查看数据的动作
  2. 在某个语言中将数据汇集为原生对象的动作
  3. 写入输出数据源的动作

完整示例

Spark可以从大量数据源中读取数据或写入数据,为了读取这些数据,需要用到与我们创建的SparkSession所关联的DataFrameReader,还需要指定文件格式及设置其他选项。为了获取模式信息,Spark会从文件中读取一些数据,然后根据Spark支持的类型尝试解析读取这些行中的数据类型。当然也可以在读取数据时选择严格指定模式

bash 复制代码
val flightData2015 = spark.read.option("inferSchema","true").option("header","true").csv("file:///data/2015-summary.csv")

csv文件被读到一个dataframe里后,又被转换为一个本地数组或行列表

在默认情况下,shuffle操作会输出200个shuffle分区,我们将此值设置为5,以减少shuffle输出分区的数量:

bash 复制代码
spark.conf.set("spark.sql.shuffle.partitions","5")

我们构建的转换逻辑计划定义了DataFrame的血统,这样在任何给定的时间点,Spark都知道如何通过对输入数据执行之前的操作来重新计算任何分区,这就是Spark编程模型的核心------函数式编程,当数据转换保持不变时,相同的输入始终导致相同的输出

DataFrame和SQL

不管使用什么语言,Spark以完全相同的方式执行转换操作,可以使用SQL或者DataFrame表达业务逻辑,并且在实际运行代码之前,Spark会将该逻辑编译到底层执行计划(可以在解释计划中看到),使用Spark SQL,可以将任何DataFrame注册为数据表或视图(临时表),并使用纯SQL对它进行查询。编写SQL查询或编写DataFrame代码并不会造成性能差异,它们都会被"编译"成相同的底层执行计划。

可以使用一个简单的方法将任何DataFrame放入数据表或视图中

bash 复制代码
flightData2015.createOrReplaceTempView("flight_data_2015")

请注意,这些计划编译后是完全相同的基本执行计划

再来执行一些更复杂的操作,在数据中找到前五个目标国家:

bash 复制代码
spark.sql("select dest_country_name,sum(count) sc from flight_data_2015 group by dest_country_name order by sc desc limit 5").show
bash 复制代码
flightData2015.groupBy("dest_country_name").sum("count").withColumnRenamed("sum(count)","destination_total").sort(col("destination_total").desc).limit(5).show
相关推荐
Cincoze-Johnny17 小时前
推进国产化安全应用Ⅳ:德承工控机DS-1202+银河麒麟操作系统Kylin V11 安装教程
大数据·kylin
程序猿炎义18 小时前
一人内容团队——用Amazon Quick Desktop实现小红书从选题到发布的全流程自动化
大数据·人工智能·microsoft·自动化·小红书
科技发布19 小时前
出海转化链路断裂,传播易如何打通全流程营销闭环?
大数据
爱学习的小可爱卢19 小时前
Git全解析(2W+长文):从原理到高频操作手册
大数据·elasticsearch·搜索引擎
远光九天1 天前
远光软件亮相2026 CIO百人会高峰论坛 分享“模数共振”新范式构建之路
大数据·人工智能
长不胖的路人甲1 天前
RabbitMQ 死信队列 DLQ
分布式·rabbitmq
可乐ea1 天前
【Redis八股|第8篇】Redis 分布式锁原理与 Redisson 使用
数据库·redis·分布式·面试题·redis八股
LitchiCheng1 天前
DGX Spark部署Isaac Sim(一键安装脚本)
大数据·elasticsearch·spark
RockHopper20251 天前
企业智能体为何应面向“活动”而非“数据”——一个架构范式的转变
大数据·人工智能·智能体·活动驱动
JustNow_Man1 天前
【openspec】存量项目中如何使用进行开发
大数据·人工智能