- RDD执行流程
- textFile() 是创建最原始的RDD,不属于transformation
- 在真正计算的时候有可能有多个阶段,有多少个阶段呢,取决于所处理的数据也没有shuffle,如果有shuffle,就被划分成两个阶段,因为需要按照一定的规律把数据分到同一个分区里面,如果有shuffle,就要切分stage,程序先执行先前的stage,然后再执行后面的stage,一个stage会有多个task,同一个stage,里面多个taask的计算逻辑是一样的,只不过各个task的计算数据不一样,
- 在textFile创建RDD中,分区中大的数据块如何做处理
- 如果textFile(),如果里面的文件大小一样,有几个block就对应几个分区,如果他们大小不一样,这个大的大于goalsize的1.1倍,goalsize,是所有的文件大小加起来,除以最小分区数,最小分区数一般默认是2,但我们可以根据具体需求指定最小分区数,如果大的文件大于goalsize的1.1倍,这个文件就会对应多个分区,到底对应几个分区呢,取决于穿进去的最小分区数,如果默认是2,那么大文件对应两个分区,以后有两个task来读取数据,但是他们不会重复读取里面的数据,只是相当于做一个逻辑划分,也就是第一个task,读取文件的那部分数据,然后第二个task继续读取之前task没有读取到的数据.如果我们就希望一个block块读取一个数据切片,那么就把最小数据切片改为1,那么一个block对应一个数据切片,
- map方法和filter方法的执行流程
- 1.启动master,和多个worker,sparkSubmit
- 2.master根worker通信,让worker启动executor,先假设每 个worker都会启动一个executor,
- 3.executor启动起来后要跟drivar反向注册,(为什么要跟driver反向注册,因为这时候,worker里面的executor已经准备好了一个执行资源的一个环境,以后等着driver给他们发送任务task),
- 4.driver里面写的是
- 创建连接,也就是创建最原始的RDD
- val sc = new SparkContext(conf)
- 创建RDD
- val lines = sc.textFile("hdfs://linux01:9000/doit16/out")
- map操作
- val nums = lines.map(_.toInt) //transformation
- filter操作
- val even =nums.filter(_%2==0) //transformation
- 保存文件到hdfs
- even.saveAsTextFile("hdfs://linux01:9000/doi16/out") //action
- 5.触发action后会生成Job,根据最后一个RDD,从后往前推,也就是找其父RDD,并且找RDD与RDD之间的关系,并且根据这些依赖关系看看也不要划分stage,如果有shuffle,就切分stage,然后继续往前推,知道最原始的RDD,(这里用到了递归算法) 该stage最后有多少个分区,就会产生多少个task,
- 6.把task(是类的实例),每个task都有一个计算逻辑,(也可以称之为计算函数)而且里面都是迭代器,(1.读数据,2.toInt,3.过滤,4.保存) 传到Worker节点的executor里面,
- 7.注意在读数据的时候,不是一下子把所有的数据读出来,而是一条一条的读出来,然后,进行相应的逻辑计算
- 8.重点:这里干活的不是RDD,而是每个RDD对应生成的Task,
- 9.Task里面的大部分的准备工作都是在Driver里面完成的,而真正的运算是在Executor里面完成,
- 逻辑的执行流程
- 1.最先生成的是HadoopRDD,里面装的是k-v类型[LongWritable,Text]
- 2.其次生成MapPartitionsRDD[String],
- 3.MapPartitionsRDD[Int] toInt
- 4.过滤 MapPartitionRDD[Int]
- 5.变成K-V 形式 MapPartition[NullWritable]
- 总结:对RDD进行操作就是对每一个分区进行操作,就是对分区内每一个Task进行操作,一个Task就持有一个迭代器,是迭代器执行里面的filter方法,执行程序传入的逻辑,