RDD的序列化和依赖
RDD的序列化
在RDD中如果在Driver中new的对象的方法和属性在Execture上有使用的话,需要将这个对象进行序列化后传递
object SerDemo {
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("CreateRDD")
val sc = new SparkContext(conf)
var rdd = sc.parallelize(Array((1, "lisi"), (1, "b"), (2, "c"),(4,"d")))
val da = new SerDemo("da")
rdd.map{
case (id,name)=> (id,da.changeName(name))
}.collect().foreach(println)
}
}
// 如果不实现序列化接口就会报错,因为调用了该对象的方法,但是不能传递这个对象,加上extends Serializable 或者创建样例类就可以
class SerDemo(val name:String){
def changeName(name1 : String) :String =name1 match {
case "lisi" => name
case x => x
}
}
// 如果调用了对象的属性,也会报not Serializable错误
RDD的依赖
RDD会记录上执行单个操作,将创建RDD的一系列Lineage记录下来,这会记录RDD的元数据信息和转换行为。当该RDD的部分分区数据丢失时,它可以根据这些信息重新计算和回复丢失的数据分区。RDD 之间的关系可以从两个维度来理解: 一个是 RDD 是从哪些 RDD 转换而来, 也就是 RDD 的 parent RDD(s)是什么; 另一个就是 RDD 依赖于 parent RDD(s)的哪些 Partition(s). 这种关系就是 RDD 之间的依赖.
依赖关系可以通过dependencies在程序中获得,依赖可以分为两种
narrow dependency
窄依赖指的是每一个父RDD的partition最多被子RDD的一个partition使用,意思是一个父分区中的数据。
wide dependency
宽依赖意味着多个RDD的partition会依赖同一个父RDD的partition,会引起shuffle过程
ShuffleDenpendency
DAG
原始的RDD经过一系列转换就会形成RDD,根据RDD之间依赖关系的不同将DAG划分为不同的stage。对于窄依赖,在一个stage中完成转换,对于宽依赖,会等parent RDD转换完之后才能转换,因此会进入一个新的stage
Spark任务的划分
- Application,一个SparkContext就会对应生成一个Application
- Job,一个Action算子就会生成一个job
- 根据RDD之间的依赖关系的不同将job分成不同的Stage
- Task,一个Stage有一个TaskSet,一个阶段中最后有几个分区就会有几个Task,其他是可以并行执行的