2021-02-21 大数据课程笔记 day32

本文深入探讨了Spark的Master启动源码,详细阐述了SparkSubmit任务提交的过程,以及Spark资源调度的源码流程和结论。通过实例展示了如何在不同场景下配置Executor资源,并讲解了Spark的二次排序和分组取topN的解决方案。
摘要由CSDN通过智能技术生成

时间煮雨
@R星校长

Spark 第四天【SparkCore 内容】

主要内容

  1. Spark Master 启动源码
  2. Spark Submit 任务提交源码
  3. Spark Driver 启动源码
  4. Spark Application 注册并分配资源
  5. Spark 资源调度结论
  6. Spark 任务调度
  7. Spark 二次排序问题
  8. Spark 分组取 topN 问题

学习目标在这里插入图片描述

第一节 Spark Master 启动
  1. Spark 资源任务调度对象关系图在这里插入图片描述
  2. 集群启动过程
    Spark 集群启动之后,首先调用 $SPARK_HOME/sbin/start-all.sh,start-all.sh 脚本中调用了 “start-master.sh” 脚本和 “start-slaves.sh” 脚本,在 start-master.sh 脚本中可以看到启动 Master 角色的主类:“org.apache.spark.deploy.master.Master”。在对应的 start-slaves.sh 脚本中又调用了 start-slave.sh 脚本,在 star-slave.sh 脚本中可以看到启动 Worker 角色的主类:“org.apache.spark.deploy.worker.Worker”。
  • Master&Worker 启动
    Spark 框架的设计思想是每台节点上都会启动对应的 Netty 通信环境,叫做 RpcEnv 通信环境。每个角色启动之前首先向 NettyRpcEnv 环境中注册对应的 Endpoint,然后启动。角色包括:Master, Worker, Driver, Executor 等。下图是启动 start-all 集群后,Master 角色启动过程,Master 角色的启动会调用 “org.apache.spark.deploy.master.Master” 主类,执行流程如下:在这里插入图片描述
第二节 Spark Submit 任务提交
  • SparkSubmit 任务提交
    Spark submit 提交任务时,调用 $SPARK_HOME/bin/spark-submit spark-submit 脚本中调用了 “org.apache.spark.deploy.SparkSubmit” 类。执行此类时,首先运行 main 方法进行参数设置,然后向 Master 申请启动 Driver。代码流程如下图示:在这里插入图片描述
  • 启动 DriverWrapper 类
    当提交任务之后,客户端向 Master 申请启动 Driver,这里首先会启动一个DriverWrapper 类来对用户提交的 application 进行包装运行,DriverWrapper 类的启动过程如下:在这里插入图片描述
  • 注册 Driver Endpoint,向 Master 注册 Application
    当执行用户的代码时,在 new SparkContext 时,会注册真正的 Driver 角色,这个角色名称为 “CoarseGrainedScheduler” , Driver 角色注册之后,注册 “AppClient” 角色,由当前这个角色向 Master 注册 Application。代码流程如下:在这里插入图片描述
第三节 Spark资源调度源码
  1. Spark 资源调度源码过程
    Spark 资源调度源码是在 Driver 启动之后注册 Application 完成后开始的。Spark 资源调度主要就是 Spark 集群如何给当前提交的 Spark application 在 Worker 资源节点上划分资源。Spark 资源调度源码在 Master.scala 类中的 schedule() 中进行的。

  2. Spark 资源调度源码结论
    1) Executor 在集群中分散启动,有利于 task 计算的数据本地化。
    2) 默认情况下(提交任务的时候没有设置 --executor-cores 选项),每一个 Worker 为当前的 Application 启动一个 Executor , 这个 Executor 会使用这个 Worker 的所有的 cores 和 1G 内存。
    3) 如果想在 Worker 上启动多个 Executor,提交 Application 的时候要加 --executor-cores 这个选项。
    4) 默认情况下没有设置 --total-executor-cores , 一个 Application 会使用 Spark 集群中所有的 cores。
    5) 启动 Executor 不仅和 core 有关还和内存有关。

  3. 资源调度源码结论验证
    使用 Spark-submit 提交任务演示。也可以使用 spark-shell 来验证。

1) 默认情况每个 worker 为当前的 Application 启动一个 Executor,这个 Executor 使用集群中所有的 cores 和 1G 内存。

./spark-submit 
--master spark://node1:7077
 --class org.apache.spark.examples.SparkPi
 ../lib/spark-examples-1.6.0-hadoop2.6.0.jar 
10000

2) 在 workr 上启动多个 Executor , 设置 --executor-cores 参数指定每个 executor 使用的 core 数量。

./spark-submit
 --master  spark://node1:7077
 --executor-cores 1 
 --class org.apache.spark.examples.SparkPi 
../lib/spark-examples-1.6.0-hadoop2.6.0.jar 
10000

3) 内存不足的情况下启动 core 的情况。Spark 启动是不仅看 core 配置参数,也要看配置的 core 的内存是否够用。

./spark-submit 
--master  spark://node1:7077 
--executor-cores 1  
--executor-memory 3g 
--class org.apache.spark.examples.SparkPi
 ../lib/spark-examples-1.6.0-hadoop2.6.0.jar 
10000

–total-executor-cores 集群中共使用多少 cores
注意:一个进程不能让集群多个节点共同启动。

./spark-submit 
--master  spark://node1:7077 
--executor-cores 1  
--executor-memory 2g 
--total-executor-cores 3
--class org.apache.spark.examples.SparkPi
 ../lib/spark-examples-1.6.0-hadoop2.6.0.jar 
10000
第四节 Spark 任务调度源码

Spark 任务调度源码是从 Spark Application 的一个 Action 算子开始的。action 算子开始执行,会调用 RDD 的一系列触发 job 的逻辑。其中也有 stage 的划分过程:在这里插入图片描述

第五节 Spark 二次排序和分组取 topN
  1. 二次排序
    大数据中很多排序场景是需要先根据一列进行排序,如果当前列数据相同,再对其他某列进行排序的场景,这就是二次排序场景。例如:要找出网站活跃的前 10 名用户,活跃用户的评测标准就是用户在当前季度中登录网站的天数最多,如果某些用户在当前季度登录网站的天数相同,那么再比较这些用户的当前登录网站的时长进行排序,找出活跃用户。这就是一个典型的二次排序场景。
    解决二次排序问题可以采用封装对象的方式,对象中实现对应的比较方法。
1.	SparkConf sparkConf = new SparkConf()
2.	.setMaster("local")
3.	.setAppName("SecondarySortTest");
4.	final JavaSparkContext sc = new JavaSparkContext(sparkConf);
5.	
6.	JavaRDD<String> secondRDD = sc.textFile("secondSort.txt");
7.	
8.	JavaPairRDD<SecondSortKey, String> pairSecondRDD = secondRDD.mapToPair(new PairFunction<String, SecondSortKey, String>() {
9.	
10.	  /**
11.	   * 
12.	  */
13.	  private static final long serialVersionUID = 1L;
14.	
15.	  @Override
16.	  public Tuple2<SecondSortKey, String> call(String line) throws Exception {
17.	    String[] splited = line.split(" ");
18.	    int first = Integer.valueOf(splited[0]);
19.	    int second = Integer.valueOf(splited[1]);
20.	    SecondSortKey secondSortKey = new SecondSortKey(first,second);
21.	    return new Tuple2<SecondSortKey, String>(secondSortKey,line);
22.	  }
23.	});
24.	
25.	pairSecondRDD.sortByKey(false).foreach(new 
26.	VoidFunction<Tuple2<SecondSortKey,String>>() {
27.	
28.	  /**
29.	   * 
30.	   */
31.	  private static final long serialVersionUID = 1L;
32.	
33.	    @Override
34.	    public void call(Tuple2<SecondSortKey, String> tuple) throws Exception {
35.	      System.out.println(tuple._2);
36.	  }
37.	});
38.	
39.	
40.	
41.	public class SecondSortKey implements Serializable,Comparable<SecondSortKey>{
42.	  /**
43.	   * 
44.	   */
45.	  private static final long serialVersionUID = 1L;
46.	  private int first;
47.	  private int second;
48.	  public int getFirst() {
49.	    return first;
50.	  }
51.	  public void setFirst(int first) {
52.	    this.first = first;
53.	  }
54.	  public int getSecond() {
55.	    return second;
56.	  }
57.	  public void setSecond(int second) {
58.	    this.second = second;
59.	  }
60.	  public SecondSortKey(int first, int second) {
61.	    super();
62.	    this.first = first;
63.	    this.second = second;
64.	  }
65.	  @Override
66.	  public int compareTo(SecondSortKey o1) {
67.	    if(getFirst() - o1.getFirst() ==0 ){
68.	      return getSecond() - o1.getSecond();
69.	    }else{
70.	      return getFirst() - o1.getFirst();
71.	    }
72.	  }
73.	}
  1. 分组取 topN
    大数据中按照某个 Key 进行分组,找出每个组内数据的 topN 时,这种情况就是分组取 topN 问题。
    解决分组取 TopN 问题有两种方式,第一种就是直接分组,对分组内的数据进行排序处理。第二种方式就是直接使用定长数组的方式解决分组取 topN 问题。
1.	SparkConf conf = new SparkConf()
2.	.setMaster("local")
3.	.setAppName("TopOps");
4.	JavaSparkContext sc = new JavaSparkContext(conf);
5.	JavaRDD<String> linesRDD = sc.textFile("scores.txt");
6.	
7.	JavaPairRDD<String, Integer> pairRDD = linesRDD.mapToPair(new PairFunction<String, String, Integer>() {
8.	
9.	/**
10.	  * 
11.	  */
12.	  private static final long serialVersionUID = 1L;
13.	
14.	  @Override
15.	  public Tuple2<String, Integer> call(String str) throws Exception {
16.	    String[] splited = str.split("\t");
17.	    String clazzName = splited[0];
18.	    Integer score = Integer.valueOf(splited[1]);
19.	    return new Tuple2<String, Integer> (clazzName,score);
20.	  }
21.	});
22.	
23.	pairRDD.groupByKey().foreach(new 
24.	VoidFunction<Tuple2<String,Iterable<Integer>>>() {
25.	
26.	  /**
27.	   * 
28.	   */
29.	  private static final long serialVersionUID = 1L;
30.	
31.	  @Override
32.	  public void call(Tuple2<String, Iterable<Integer>> tuple) throws Exception {
33.	    String clazzName = tuple._1;
34.	    Iterator<Integer> iterator = tuple._2.iterator();
35.	
36.	    Integer[] top3 = new Integer[3];
37.	
38.	    while (iterator.hasNext()) {
39.	      Integer score = iterator.next();
40.	
41.	      for (int i = 0; i < top3.length; i++) {
42.	        if(top3[i] == null){
43.	          top3[i] = score;
44.	          break;
45.	        }else if(score > top3[i]){
46.	        for (int j = 2; j > i; j--) {
47.	          top3[j] = top3[j-1];
48.	        }
49.	        top3[i] = score;
50.	        break;
51.	      }
52.	    }
53.	  }
54.	  System.out.println("class Name:"+clazzName);
55.	  for(Integer sscore : top3){
56.	    System.out.println(sscore);
57.	  }
58.	}
59.	});

本节作业

  1. Spark 底层代码设计思想,以 Master 为例介绍?
  2. Spark 资源调度源码流程?
  3. Spark 资源调度源码结论?
  4. 二次排序和分组取 topN 问题代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值