文章目录
介绍大致功能,Spark的核心术语和概念。包括集群计算的核心体系结构和Spark应用程序,并结合DataFrame和SQL介绍Spark结构化API。
Spark的基本架构
Spark是一种管理和协调跨多台计算机的计算任务的软件框架。执行计算任务的若干台机器由像Spark的集群管理器、YARN或Mesos这样的集群管理器管理,我们提交Spark应用程序给集群管理器,它们将计算资源分配给应用程序,完成工作。
Spark应用程序
Spark应用程序由一个驱动器进程和一组执行器进程组成。
驱动进程运行main()函数,位于集群中的一个节点上,它负责三件事:维护Spark应用程序的相关信息;回应用户的程序或输入;分析任务并分发给若干执行器执行处理。驱动器是必须的,它是Spark应用程序的核心,他在应用程序执行的整个生命周期中维护着所有相关信息。
执行器负责执行驱动器分配给它的实际计算任务,这意味着每个执行器只负责两件事:执行由驱动器分配给它的代码,并将该执行器的计算状态报告给运行驱动器的节点。
- Spark使用一个集群管理器来跟踪可用的资源
- 执行器进程负责执行驱动器的命令来完成给定的任务
执行器大部分时候都运行Spark代码,但是驱动器可以通过多种不同语言调用Spark API来“驱动”。
Spark API的多语言支持
Spark API的多语言支持允许使用多种编程语言运行Spark代码。我的理解就是在外面包了一层解释层。
Spark的API
虽然你可以使用各种语言启动Spark任务,但是这些语言提供的内容需要详细介绍。Spark有两套基本的API,低级“非结构化”API和更高级别的结构化API。
启动Spark
通过运行第一章给出的命令来启动Spark,此时隐式的创建了一个交互式的SparkSession(用来管理Spark应用程序)。若不是通过交互式模式启动而是通过独立应用程序启动Spark时,你必须在应用程序代码中显式地创建SparkSession对象。
SparkSession
我们需要通过名为SparkSession的驱动器来控制Spark应用程序,需要创建一个SparkSession实例来在集群中执行用户定义的操作,每一个Spark应用程序都需要一个SparkSession与之对应。当我们以交互式命令启动一个客户端时,这个SparkSession就被实例化了一个名为Spark的对象。
DataFrame
DataFrame是最常见的结构化API,简单来说,它是包含行和列的数据表。说明这些列和列类型的一些规则被称为模式(schema)。DataFrame概念并不是Spark独有的,R和Python都有相似的概念,差别在于单机还集群处理。
Spark有几个核心抽象:Dataset,DataFrame,SQL表和弹性分布式数据集(Resilient Distributed Datasets,RDD)。这些不同的抽象都表示分布式数据集合,其中最简单和高效的是DataFrame。
数据分区
为了让多个执行器并行地工作,Spark将数据分解成多个数据块,每个数据块叫做一个分区。分区是位于集群中的一台物理机上的多行数据的集合,DataFrame的分区也说明了在执行过程中数据在集群中的物理分布。
转换操作
Spark的核心数据结构在计算过程中是保持不变的,这意味着它们在创建之后无法更改。要“更改”DataFrame,你需要告诉Spark如何修改它以执行你想要的操作,这个过程被称为转换。
转换操作是使用Spark表达业务逻辑的核心,有两类转换操作:第一类是指定窄依赖关系的转换操作,第二类是指定宽依赖关系的转换操作。
- 窄转换:每个输入分区仅决定一个输出分区的转换。
- 宽转换:每个输入分区决定了多个输出分区。也叫做洗牌(shuffle) 操作,它会在整个集群中执行互相交换分区数据的功能。
如果是窄转换,Spark将自动执行流水线处理,这意味着如果我们在DataFrame上指定了多个过滤操作,它们将全部在内存中执行。而属于宽转换的shuffle操作不是这样,当我们执行shuffle操作时,Spark将结果写入磁盘。
惰性评估
惰性评估的意思就是等到绝对需要时才执行计算。在Spark中,当用户表达一些对数据的操作时,不是立即修改数据,而是建立一个作用到原始数据的转换计划。Spark首先会将这个计划编译为可以在集群中高效运行的流水线式的物理执行计划,然后等待,直到最后时刻才开始执行代码。
DataFrame的谓词下推有点数据库优化器的味道了。
动作操作
转换操作使我们能够建立逻辑转换计划。为了触发计算,我们需要运行一个动作操作(action)。一个动作指示Spark在一系列转换操作后计算一个结果。
三类动作:
- 在控制台中查看数据的动作
- 在某个语言中将数据汇集为原生对象的动作
- 写入输出数据源的动作
Spark用户接口
你可以通过Spark的Web UI监控一个作业的进度,Spark UI占用驱动器节点的4040端口。Spark UI上显示了Spark作业的运行状态、执行环境和集群状态等信息,这些信息非常有用,可用于性能调优和代码调试。
一个Spark作业包含一系列转换操作并由一个动作操作触发,并可以通过Spark UI监视该作业。
一个完整的例子
我们不能操纵物理数据,但是我们可以配置参数来执行物理执行的特性。
我们构建的转换逻辑计划定义了DataFrame的血统,这样在任何给定的时间点,Saprk都知道如何通过对输入数据执行之前的操作来重新计算任何分区,这就是Saprk编程模型的核心 - 函数式编程,当数据转换保持不变时,相同的输入始终导致相同的输出。
DataFrame和SQL
无论使用什么语言,它们最终都会被“编译”成相同的底层执行计划,不会产生性能差异。
DataFrame的执行计划:(和数据库的执行计划差不多,异曲同工)
- 读取数据
我们之前定义了DataFrame,但是Spark实际上并没有真正读取它,直到在DataFrame上调用动作操作后才会真正读取它。 - 分组
当调用groupBy时,我们最终得到了一个RelationalGroupedDataset对象,他是一个DataFrame对象,具有指定的分组,但需要用户指定聚合操作,然后才能进一步查询。我们按键(或键集合)分组,然后再对每个键对应的分组进行聚合操作。 - 指定聚合操作
结果产生一个新的DataFrame,它有一个新的表结构,并知道每个列的类型。 - 简单的重命名
我们使用带有两个参数的withColumnRenamed方法,即原始列名称和新列名称。 - 对数据进行排序
按照某种规则对数据进行排序。 - 指定限制
对最终返回的数据进行限制。 - 我们要执行的动作
现在我们实际上才开始收集DataFrame的结果,Spark将返回一个我们所使用语言的数组或列表。
小结
Apache Spark的基础知识。转换和动作,惰性执行转换操作的DAG图来优化DataFrame上的物理执行计划。如何将数据组织到分区中,并为处理更复杂的转换设定多个阶段。