大数据开发Spark高级特性(第三十三篇)

139 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情

一、宽依赖和窄依赖

  1. 窄依赖(Norrow Dependency)指父RDD的每个分区只被子RDD的一个分区所使用,例如:map、filter等

  2. 宽依赖(Shuffle Dependency)父RDD的每个分区都可能被子RDD的多个分区使用,例如:groupByKey、reduceByKey

    每个父RDD的partition中的数据都可能会传输一部分到一个RDD的每个partition中。此时父RDD与子RDD会产生复杂的关系

Hadoop-宽依赖、窄依赖.drawio

二、Stage

  1. Spark Job会被划分为多个stage,每一个stage是由一组并行的task组成的
  2. Stage的划分依据就是看是否产生了Shuflle(即宽依赖),遇到一个Shuffle操作就会被划分为前后两个Stage

三、Spark Job三种提交模式

  1. Standalone模式
  2. yarn client模式
  3. yarn cluster模式

Spark Job提交任务的三种方式

四、shuffle机制

4.1、未优化的Hash Based Shuffle

假设一个节点,节点上有2个CPU,上面运行了4个ShuffleMapTask。每个ShufffleMapTask都会为每个Reduce Task创建一份Bucket缓存,以及对应的ShuffleBlockFile磁盘文件。

如果有100个map task。100个result task ,那么本地磁盘会产生10000个文件,磁盘io过多,影响性能

4.2、优化后的Hash Based Shuffle

Spark引入了Consolidtion机制,一个ShuffleMapTask将数据写入ResultTask数量的本地文件中,这个是不变的,但是当下一个ShuffleMapTask运行的时候,可以直接将数据写入之前的ShuffleMapTask的本地文件中,相当于对多个ShuffleMapTask的输出进行了合并,从而减少了本地磁盘文件中文件的数量

此时文件的数量编程了cpu core数量* result task数量,比如每个节点上有2个CPU,有100个result task,那么每个节点上会产生200个文件

4.3、Sort-Based Shuffle

ShuffleMap Task会写入同一个文件

五、checkpoint(类似快照机制)

比如spark任务比较复杂,从初始化rdd开始到最后整个任务完成,有比较多的步骤。比如有超过10个的运算子,而且整个任务运行的时间比较长。比如适合checkpoint

针对Spark Job,如果我们担心某些关键的,在后面会反复使用的RDD,因为节点故障导致数据丢失,那么可以针对该RDD启动checkpoint机制,实现容错和高可用

  1. 首先调用SparkContext的setCheckpointDir()方法,设置一个容错的文件系统目录(HDFS),然后对RDD调用checkponit()方法
5.1、RDD之checkpoint流程
  1. SparkContext设置checkpoint目录,用于存放checkponit的数据,对RDD调用checkpoint方法,然后它就会被RDDCheckpointData对象进行管理,此时这个RDD的checkpoint状态会被设置为Initialized
  2. 待RDD所在的job运行结束,会调用job中最后一个RDD的doCheckpoint方法,该方法沿着RDD的血缘关系向上查找被checkpoint()标记过的RDD,并将其checkpoint状态从Initialized设置为CheckpointInProcess
  3. 启动一个单独的job,来将血缘关系中标记为CheckpointInProcess的RDD执行checkpoint操作,也就是将其数据写入checkpoint目录
  4. 将RDD数据写入checkpoint目录之后,会将RDD状态改变为checpointed,并且还会改变RDD的血缘关系,即会清除掉RDD所有依赖的RDD,最后还会设置其父RDD为新创建的checkpointRDD
5.1、checkpoint与持久化的区别
  1. lineage是否发生改签

  2. 丢失数据的可能性

    • checkpoint是存储在hdfs中
    • 持久化是存储在内存中
    • 建议:对需要checkpoint的rdd,先执行persist(StorageLevel.DISK_ONLY)
scala
package com.strivelearn.scala
​
import org.apache.spark.{SparkConf, SparkContext}
​
/**
 * @author strivelearn
 * @version CheckPointOpScala.java, 2022年11月26日
 */
object CheckPointOpScala {
  def main(args: Array[String]): Unit = {
    //创建SparkContext
    val conf = new SparkConf()
    conf.setAppName("CheckPointOpScala")
      .setMaster("local")
    val context = new SparkContext(conf)
​
    //1.设置checkPoint目录
    context.setCheckpointDir("hdfs://xxx")
​
    val dataRdd = context.textFile("hdfs://xxx")
​
    //2.对rdd执行checkPoint操作
    dataRdd.checkpoint()
​
    dataRdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _).saveAsTextFile("hdfs://xxx")
    context.stop()
  }
}
​
java
package com.strivelearn.java;
​
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import scala.Tuple2;
​
import java.util.Arrays;
​
/**
 * @author strivelearn
 * @version CheckpointOpJava.java, 2022年11月26日
 */
public class CheckpointOpJava {
    public static void main(String[] args) {
        //1.创建sparkContext
        SparkConf sparkConf = new SparkConf();
        sparkConf.setAppName("CheckpointOpJava");
        sparkConf.setMaster("local");
        JavaSparkContext javaSparkContext = new JavaSparkContext(sparkConf);
        //1.设置checkpoint目录
        javaSparkContext.setCheckpointDir("hdfs://xxx");
        JavaRDD<String> stringJavaRDD = javaSparkContext.textFile("hdfs://xxx");
        //2.对rdd执行checkpoint操作
        stringJavaRDD.checkpoint();
​
        stringJavaRDD.flatMap(line -> Arrays.asList(line.split(" ")).iterator()).mapToPair(word -> new Tuple2<>(word, 1)).reduceByKey((x, y) -> x + y).saveAsTextFile("hdfs://xxx");
​
    }
}
JavaRDD<String> stringJavaRDD = javaSparkContext.textFile("hdfs://xxx")
                                                //开启持久化
                                                .persist(StorageLevel.DISK_ONLY());