编写Spark应用程序
Spark应用程序包含两个部分:一个是Spark集群,另一个是你的代码。在本例中,集群被设置为本地模式,应用程序是预定义的
一个简单的基于Scala的应用程序
Scala可以说是Spark的母语,因为Spark系统本身就是Scala编写的,使用Scala自然而然地成为编写应用程序的好方法,这样的话编写Spark应用程序和编写Scala应用程序没什么不同
你可以使用sbt或Apache Maven来构建应用程序,这是两个基于Java虚拟机(JVM)的程序构建工具,与任何程序构建工具一样,他们有各自的使用特点。使用sbt构建可能是更简单些,你可以在sbt官方网站上下载sbt,安装并了解sbt,你也可以从Maven的官方网站上下载Maven,然后安装Maven
使用sbt构建Scala应用程序,我们需要修改build.sbt文件来配置软件包依赖信息。在build.sbt文件里面,包括以下几个关键的信息需要设置:
- 项目元数据(包名称,包版本信息等)
- 在哪里解决依赖关系
- 构建库所需要的包依赖关系
注意在build.sbt文件中,必须指定scala的版本以及spark版本
配置应用程序
Spark涉及许多配置选项,大多数配置选项分为以下几类:
应用程序属性
运行时环境
shuffle行为
SparkUI
压缩和序列化
内存管理
执行行为
网络
调度
动态分配
安全
加密
SparkSQL
Spark流处理
SparkR
你可以通过三种手段配置Spark系统:
- Java属性配置
- 硬编码的配置文件
- 通过Spark属性可以控制大多数应用程序参数,可以通过SparkConf对象进行设置
SparkConf
SparkConf管理着我们所有的应用配置,首先需要使用import语句并创建一个SparkConf对象,在创建SparkConf对象之后,SparkConf对象将不可以改写:
c
import org.apache.spark.SparkConf
val conf = new SparkConf().setMaster("local[2]").setAppName("DefinitiveGuide")
你可以使用SparkConf来配置每个Spark应用程序的Spark属性,这些Spark属性包括如何控制Spark应用程序的运行方式以及如何配置集群。
应用程序属性
应用程序属性可以通过spark-submit命令行配置或从代码创建Spark应用程序时配置。他们定义了基本的应用程序元数据以及一些执行特性。
环境变量
你可以通过环境变量来配置Spark的某些参数,这些环境变量的默认位置是在Spark根目录下的conf/spark-env.sh脚本中读取的,在Standalone模式和Mesos模式下,该文件可以提供特定主机的信息,例如主机名。此外,本地运行Spark应用程序或提交脚本时,他也会被读取和加载。
请注意,默认情况下在安装Spark后并不存在conf/spark-env.sh文件,需要复制conf/spark-env.sh.template来创建它,并且请赋予该文件具有可执行权限。
应用程序之内的调度
在给定的Spark应用程序中,如果多个并行作业是从不同的线程提交的,它们可以同时运行,Spark作业的意思是一个Spark动作以及执行该动作对的所需要启动的任务。Spark的调度是完全线程安全的,使应用程序支持多个请求(例如,来自多个用户的查询请求)
默认情况下,Spark遵循FIFO(先进先出)方式调度作业,如果位于队列头的作业不需要使用整个集群资源,后面的作业可以立即开始,,但如果队列头的作业工作量很大,位于队列后部的作业可能会被延迟启动。
也可以配置作业之间公平共享集群资源。Spark以轮询方式调度各作业并分配任务,以便所有作业获得大致相等的集群资源份额。这意味着当一个大作业正在运行并占用集群资源时,新提交的小作业可以立即获得计算资源并被启动,无需等待大作业的结束再开始,所以可以获得较短的响应时间,此模式最适合多用户情况。要启用公平调度,需要在配置SparkContext时将spark.scheduler.mode属性设置为FAIR。
公平调度程序还支持将作业分组到作业池中,并为每个池设置不同的调度策略或优先级。可以为更重要的作业创建高优先级作业池,也可以将每个用户的工作组合在一起配置一个作业池,并为每个用户分配相同的调度资源,而不管他们的并发作业有多少,这种方法类似Hadoop的Fair Scheduler。
默认情况下,新提交的作业会进入默认池,也可以通过SparkContext设置作业要提交到的作业池,即设置spark.scheduler.pool属性。这可以按如下方法完成,假定sc是你的SparkContext:
sc.setLocalProperty("spark.scheduler.pool","pool1")
设置此本地属性后,此线程提交的所有作业将使用此作业池名称。该设置是按线程进行配置的,以便让代表同一用户的线程可以配置多个作业。如果你想清除该线程关联的作业池,请将该属性设置为null。