Spark应用:driver program运行用户main函数并在executors集群执行并行操作
1 Spark提供两种抽象:RDD和shared variables
2 创建RDD的两种方式:在驱动器程序parallelize集合;从外部存储系统引入数据集
1) SparkContext.parallelize
可以使用第二个参数传递分区数量,即并行度,sc.parallelize(data, numSlices)
2) 外部存储系统包括本地文件系统,HDFS,Cassandra,HBase,Amazon S3,并支持文本文件,SequenceFile,和其他的Hadoop InputFormat
> textFile返回文件的每一line作为一条记录
> 文件系统的路径要可被所有工作节点访问
> textFile方法支持路径,压缩文件,wildcards(通配符)
textFile("/my/directory")/textFile("/my/directory/*.txt")/textFile("/my/directory/*.gz").
> textFile的第二个参数也是分区数量,并行分区数量不能少于文件块的数量(HDFS)
3)除了textFile方法,Scala API还提供了
> SparkContext.wholeTextFiles,读取一个文件路径,返回(filename, content)pair RDD
> SparkContext.sequenceFile[K, V]读取SequenceFile
> 其他HadoopInputFormats,使用SparkContext.hadoopRDD,使用SparkContext.newAPIHadoopRDD读取new MR API(org.apache.hadoop.mapreduce)
> RDD.saveAsObjectFile和SparkContext.objectFile支持序列化Java对象的方式保存RDD,不过没有Avro有效率
3 RDD Operations: Transformations and Actions
1) 转化操作都是惰性求值的
2) textFile也是惰性的,val lines = sc.textFile(file),lines只是对文件的引用,实际action操作才会进行计算
5 Spark Cluster使用闭包
> 统计信息时不使用driver自定义外部变量,使用Accumulator累加器,因为自定义外部变量虽然可能在本地有效,但在集群中因为在把driver变量的值复制给各个executor之后,driver中的外部变量对executor不可见,所以在executor中所做的修改并不会应用到driver的变量上,最终driver上的变量还是原来的值,并没有被executor改变
var counter = 0
var rdd = sc.parallelize(data)
// Wrong: Don't do this!!
rdd.foreach(x => counter += x)
println("Counter value: " + counter)
> 变量和方法的作用范围和生命周期,考虑本地模式还是集群模式,考虑行动操作还是转化操作
6 输出RDD元素
> 对于单机模式,可以使用rdd.foreach(println)/rdd.map(println),但在Cluster中,这样调用会把输出打印到各个executor的stdout标准输出上,而不是driver的stdout上,所以driver不会有输出
> 如果需要把cluster的RDD的所有内容输出到driver上,使用collect(),collect()会把RDD所有内容返回给driver内存,rdd.collect().foreach(println),但RDD太大时导致driver内存不足,可使用take()取部分输出,rdd.take(100).foreach(println)
7 Pair RDD
> Scala中使用Tuple2对象表示[K ,V]
> 使用自定义对象作为Key时,要实现hashCode()和equals()方法
10 RDD持久化缓存
> 持久化RDD,每个节点都把自己计算的分区结果保存在内存中,在之后的操作中可以复用,这一般可以提升10倍的计算速度
> 如果RDD中的一个分区丢失,则自动重算这个分区
> StorageLevel,LRU算法自动替换移除,如果需要主动移除,可以调用rdd.unpersist()
11 如何选择StorageLevel?
1) 首选MEMORY_ONLY,这样CPU效率最高,如果合适就使用这种
2) 次选MEMORY_ONLY_SER,使用序列化对象节省空间,CPU效率也高
3) 最好不要写到磁盘DISK,数据量很大时可能读取DISK内容的时间和重算的时间还差不多
4) 如果需要快速失败恢复,使用replicated storage levels,如MEMORY_ONLY_2,在两个不同节点分别保存同一分区
> 容错机制可以通过自动重算实现,也可以通过保存副本实现
1) Spark把函数传递executors执行时,把函数使用到的变量也拷贝到各个executor,在executor上进行的更新不会传回给driver程序,所以Spark提供共享变量 broadcast和accumulator可以解决这种问题