1、使用SparkConf配置Spark
在Scala中使用SparkConf创建一个应用
// 创建一个conf对象
val conf = new SparkConf()
conf.set("spark.app.name", "My Spark App")
conf.set("spark.master", "local[4]")
conf.set("spark.ui.port", "36000") // 重载默认端口配置
// 使用这个配置对象创建一个SparkContext
val sc = new SparkContext(conf)

SparkConf 实例包含用户要重载的配置选项的键值对。Spark中的每个配置选项都是基于字符串形式的键值对。

Spark允许通过spark-submit工具动态设置配置项。

//在运行时使用标记设置配置项的值
 bin/spark-submit \
--class com.example.MyApp \
--master local[4] \
--name "My Spark App" \
--conf spark.ui.port=36000 \
myApp.jar

一旦传给了SparkContext的构造方法,应用所绑定的SparkConf就不可变了。

Spark程序中,默认配置优先级最高为set方法,其次是spark-submit,再次是写在配置文件中的值,最后是系统的默认值。

常用的Spark配置项

选项

默认值

备注

spark.executor.memory(–executor-memory)

512m

为每个执行器进程分配内存

spark.executor.cores(–executor-cores)

1

YRRN模式下,分配给任务的核心数目

spark.cores.max(–total-executor-cores)

独立模式和Mesos模式下,设置执行器进程使用的核心上限

spark.speculation

false

设置为true时,开启任务预测执行机制,当出现速度比较慢的嗯五十,这种机制会在另外的节点上尝试执行该任务的一个副本,帮助减少个别较慢的任务带来的影响

spark.storage.blockmanagerTimeoutInterValMs

45000

内部用来通过超市机制追踪执行器进程是否存货的阈值。对于会引发长时间垃圾回收(GC)暂停的作业,需要将这个值调到100000(100秒)以上来防止失败

spark.executor.extraJava


自定义如何启动执行器进程的JVM,添加额外的java参数

spark.executor.extraClassPath


自定义如何启动执行器进程的JVM,添加额外的ClassPath

spark.executor.extra.LibraryPath


自定义如何启动执行器进程的JVM,添加额外的程序库路径

spark.serializer

org.apache.spark.serializer.JavaSerializer

指定用来进行序列化的类库,包括通过网络传输数据或缓存数据时的序列化。默认java库很慢,可以使用org.apache.spark.serializer.KryoSerializer并对Kryo进行适当的调优

spark.[X].port

任意值

用来设置运行Spark应用是用到的各个端口。X:driver,fileserver,broadcast,replClassServer,blockManager以及executor

spark.eventLog.enabled

false

设为true时,开启事件日志。

spark.eventLog.dir

file:///tmp/spark-events

开启事件日志时,事件日志的存储位置。

几乎所有Spark配置都发生在SparkConf的创建过程中,但你需要将conf/spark-env.sh中的环境变量SPARK_LOCAL_IDRS设置为用逗号隔开的存储位置列表,来指定SPark用来混洗的本地存储路径,这需要在独立模式和Mesos模式下设置。

2、Spark执行的组成部分:作业、任务和步骤
//在Scala版本的Spark shellz中处理文本数据
// 读取输入文件
scala> val input = sc.textFile("input.txt")
// 切分为单词并且删掉空行
scala> val tokenized = input.
| map(line => line.split(" ")).
| filter(words => words.size > 0)
// 提取出每行的第一个单词(日志等级)并进行计数
scala> val counts = tokenized.
| map(words = > (words(0), 1)).
| reduceByKey{ (a,b) => a + b }

这一系列命令生成了一个叫做counts的RDD,其中包含各级别日志对应的条目数。shell执行完这些命令后,程序没有执行任何行动操作。程序定义了一个RDD独享的有向无环图,每个RDD维护了其只想一个或多个父节点的引用,以及表示其与父节点之间关系的信息。这些引用可以使得RDD追踪到其所有的祖先节点。

RDD图与执行步骤的对应关系并不一定是一一对应的,当调度器进行流水执行,或把多个RDD合并到一个步骤中时。当RDD不需要混洗数据就可以从父节点计算出来时,调度器就会自动进行流水线执行。

当一个RDD已经缓存在集群内存或磁盘上时,Spark的内部调度也会自动截短RDD谱系图,直接基于缓存数据计算。还有一种截短发生在当RDD已经在之前的数据混洗中作为副产品物化出来时,及时没有被显示调用persist()方法。

特定的行动操作所产生的集合被称为一个作业,一旦步骤确定下来,任务就会被创建出来并发给内部的调度器。

一个物理步骤会启动很多任务,每个任务都是在不同的数据分区上做同样的事情。任务内部流程是一样的。

1、从数据存储或已有RDD或数据混洗输出中获取输入数据。
2、执行必要操作来计算这些操作所代表的RDD。
3、把输出写到一个数据混洗文件中,写入外部存储,或者发回驱动器程序。

spark 执行流程

1、用户代码定义RDD的有向无环图

2、行动操作把有向无环图强制转译为执行计划

一个作业包含一个或多个步骤,每个步骤是一波并行执行的计算任务。一个步骤对应有向无环图中的一个或读个RDDD(对应多个RDD是因为发生了流水线执行)。

3、任务于集群调动并执行

序列化格式

如果Spark需要通过网络传输数据,或将数据写到磁盘上,Spark需要把数据序列化为二进制。序列化在混洗时发生,使用Java的序列化库,同时也支持第三方序列化库Kryo,kryo可以提供比Java的序列化工具更短的序列化时间和更高压缩比的二进制表示,但不能直接序列化全部类型的对象,几乎所有的应用都在迁移到Kryo后获得更好的性能。

内存管理

RDD存储:调用RDD的persist()或cache方法,RDD分区会被存储到缓存中,Spark会根据spark.storage.memoryFraction限制缓存内存占整个JVM堆空间的比例大小超出限制,旧分区数据会被移除内存。

数据混洗与聚合的缓存区:进行数据混洗时,Spark会创建一些中间缓存区来存储数据清洗的中间数据以及输出数据。Spark会尝试根据Spark.shuffle.memoryFraction限定缓存区内存占总内存的比例。

用户代码:Spark可以执行任意的用户代码,所以用户的函数可以自行申请大量内存。用户代码可以访问JVM堆空间中除分配给RDD存储和数据混洗存储以外的全部剩余空间。

默认情况下,60%空间存储RDD,20%空间存储数据混洗操作产生的数据,20%留给用户程序

Spark默认cache操作会以memory_only的存储等级持久化数据。RDD分区空间不够时,旧分区直接删除,再用到数据时重新计算。以MEMORY_AND_DISK的存储级别Persist()方法调用效果更好,内存中放不下的旧分区会被写入硬盘。

对于缓存序列化后的对象而非直接缓存,通过MEMORY_ONLY_SER或MEMORY_AND_DISK_SER的存储等级来实现这一点。

硬件供给

在各种部署模式下,执行器节点的内存可以通过spark.executor.memory配置或者spark-submit的–executor-memory标记来设置。YARN模式下,可以通过spark.executor.cores或–excecutor-cores标记来设置执行器节点的核心数。