上一期中,通过翻译与凝练《Spark – The Definitive Guide》,我们初步解决了Spark是什么的问题,今天我们将继续学习Spark的基本架构,应用程序,结构化API,核心术语与概念,分享过程中若有错谬,欢迎拍砖。

Charpter 2.A Gentle Introduction to Spark
Spark’s Basic Architecture

  我们可以在一台计算机中,完成看电影,发邮件,制作电子表格等功能。但是像大数据处理这种任务,单机往往是无法胜任,因其并不具备强大的计算能力,丰富的计算资源,用户也需要花费大量时间成本等待计算结束。因而如果整合了一个集群或一组计算机资源,我们就能像单机一样使用这些资源。光有机器还不足以产生强大算力,我们还需要一个软件框架,来协调它们之间的工作,Spark由此应运而生。Spark负责管理和协调多机计算任务。其中,多台计算机会先提交Spark应用程序给集群管理器(Spark集群管理器,YARN,Mesos等管理器),Spark再根据集群管理器跟踪到可用资源,并将这些计算资源分配给应用程序。

Spark Applications

  Spark Applications(应用程序)由一个driver process(驱动器进程)和一组executor process(执行器进程)组成。executor在大多时候都运行着Spark代码,而driver则可以通过调用不同种语言的Spark API 来进行驱动。
  driver是Spark应用程序的核心,其位于集群的一个节点上。main()函数就是运行在driver process之上。driver的主要职责是:1、维护Spark应用程序的相关信息;2、响应程序或响应输入;3、任务分析并向若干executor process进行分发处理。
  executor负责两件事:1、执行由driver分配的代码逻辑或计算任务;2、将executor计算状态上报至运行driver的节点。
  下图展示了集群管理器如何控制物理机,并为Spark应用程序分配资源的过程。一个集群可以运行多个Spark应用程序,且有多个节点,用户可以配置每个节点上运行多少个executor。



spark权威指南中文下载 spark the definitive guide_big data


  除了集群模式, Spark也能在本地运行。由于驱动器和执行器只是简单的进程,这就意味着它们可以位于同一台或不同的物理机上。在本地(单机)模式下,driver和executor是线程而不是进程。

Spark’s Language APIs

  Spark API支持多种语言,用户可以使用多语言运行Spark编码(Scala,Java,Python,SQL,R)。大多时候, Spark会在每种语言中提供“核心概念”,这些概念会被转换成能在集群上运行的Spark代码。



spark权威指南中文下载 spark the definitive guide_spark权威指南中文下载_02


  上图为一个简单例子,它说明了SparkSession与Spark API间的关系。对于每种语言的API,都含有“核心概念”。图中的 SparkSession对象是Spark代码的入口,例子基于Python和R使用了Spark,这里并不是显式调用JVM指令,而是通过向SparkSession传递Python和R代码, Spark会将它们转换为可在JVM上运行的代码。

Spark’s APIs

  用户可以用各种语言启动Spark任务,主要归功于Spark的两套基本API:低级的非结构化 API和高级的结构化API。

Starting Spark

  截至目前,我们已经了解了Spark Applications(应用程序)的相关概念,但这些概念还比较抽象,当真正开始编写Spark应用程序时,需要一种能将用户指令和数据发送给Spark的方法,这就是SparkSession。按上期博文介绍的方法,我们可以通过spark-shell打开Scala控制台,来启动一个交互式会话。

  之后还会详细介绍spark-submit,它可以向Spark提交预编译应用程序或指令。

  当以交互模式启动Spark时,相当于隐式创建了一个SparkSession,来对Spark应用程序进行管理。如果不通过交互模式,比如用独立应用程序来启动Spark,则必须在程序中显式创建一个SparkSession对象。

SparkSession

  SparkSession是一个用来控制Spark应用程序的driver process。将它实例化后,Spark可以通过集群执行用户定义的操作,Spark Application和SparkSession需要一一对应。当你用Scala或Python启动控制台时,SparkSession会被实例化为一个名为spark对象。



spark权威指南中文下载 spark the definitive guide_spark_03


DataFrame

  下面执行一个简单的任务。创建一列包含1000行,值为0~999的分布式集合,在集群上运行图中命令时,集合的每个部分会被分配到不同执行器上,这个集合就是一个DataFrame。



spark权威指南中文下载 spark the definitive guide_spark权威指南中文下载_04

  作为最常见的结构化API,我们可以将DataFrame想象为具有多个命名列和行数据的表格。定义这些列和类型的规则被称为schema(模式)。和传统电子表格相比,DF最大的特点就是数据不必只存于单机上,数据量太大会使得存储和计算性能下降。

spark权威指南中文下载 spark the definitive guide_spark权威指南中文下载_05


Partitions

  为了让多个executor并行工作, Spark将数据分解成多个数据块,每个数据块为一个分区。分区是位于集群中一台物理机上的多行数据集合, DataFrame的分区表示了执行过程中数据在集群中的物理分布。如果只有一个分区,和多个executor, Spark只能在一个executor上处理数据。同理,如果有多个分区,一个executor,Spark也只有一个executor在处理数据。使用DataFrame时不一定要手动操作分区,只需要指定数据高级转换操作,Spark便会自动分配集群资源。低级别API(RDD)中也存在这种机制。

Transformations

  Spark的核心数据结构在计算过程中始终保持不变,即在创建后无法更改。为了“更改”DataFrame,你需要告诉Spark想要如何修改它,这个过程被称为Transformation。下面执行一个简单的转换操作来查找当前DF中的偶数集。以前文构建的myRange变量为例。



spark权威指南中文下载 spark the definitive guide_big data_06

  实际上Transformation并没有实际输出,我们从上图也能看出,Spark在调用action(下文会介绍)之前, 是不会真的去“更改”DF。转换仅仅是Spark表达业务逻辑的方式。

  转换操作有两种:窄依赖,宽依赖。
  具有窄依赖关系(narrow dependency)的转换操作(窄转换),指的是每个输入分区仅决定一个输出分区。上图示例中, where语句指定的就是一个窄依赖关系。



spark权威指南中文下载 spark the definitive guide_big data_07

  具有宽依赖关系(wide dependency)的转换操作(宽转换),指的是每个输入分区决定了多个输出分区。这种宽依赖关系的转换也被称为shuffle(洗牌)操作,它会在集 群中执行分区交换数据功能。 反之如果是窄转换, Spark则会自动执行流水线处理。 如果我们在DataFrame上指定了多个过滤操作,它们将全部执行在内存中。而对于宽转换的shuffle, Spark则会将结果写入磁盘。

spark权威指南中文下载 spark the definitive guide_spark权威指南中文下载_08


Lazy Evaluation

  惰性机制的意思是,直到最后时刻才会进行计算。当用户需要操作数据时,Spark首先会建立一系列作用于原始数据的转换计划,并将其编译为可在集群中高效运行的流水线式物理流程,直到触发action时,再开始执行代码。这样做的好处是,Spark可以优化从输入到输出的整个数据流。比如DataFrame的predicate pushdown(谓词下推),当我们构建了一个含有多个转换操作的Spark作业,并在最后指定了一个过滤操作(假设只需要输入的某一行数据),那么显然从最开始就仅访问那一条记录会更加高效,Spark由此实现了整个物理执行计划的优化。

Actions

  转换操作用来建立逻辑转换计划。为了触发计算,我们需要使用一个action操作。该操作告诉Spark需要在一系列转换操作后,计算出一个结果。最简单的action是count,它用来计算一个DataFrame中的记录总数,仍以上文的代码变量为例。



spark权威指南中文下载 spark the definitive guide_学习_09

  aciton主要分为三类:1、在控制台中查看数据;2、根据不同语言,将数据收集并转换为本地对象;3、写入输出数据。

Spark UI

  举个示例,当用户启动了一个Spark作业,这个作业首先执行了一次filter(窄转换),再执行一次aggregation(宽转换),再到每个分区上执行count,最后通过collect将所有分区的结果汇集到一起,生成一个结果。
  我们可以通过Spark UI看到所有上述过程。Spark UI是包含在Spark软件包中的工具,可以用来监视集群上运行的作业。Spark UI占用的driver节点端口为4040。如果是用本地模式运行,也可以通过http://localhost:4040访问Spark Web UI。Spark UI上还显示了作业的运行状态,作业进度,执行环境和群集状态等信息,这些信息非常有用,可以用来调优性能和调试代码。从下图可以看出,该作业包含了两个运行阶段,九个任务。



spark权威指南中文下载 spark the definitive guide_spark_10