Spark基本原理介绍

Spark程序流程介绍

package cn.edu360.spark;
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 org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
import java.util.Arrays;
import java.util.Iterator;

public class JavaWordCount {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("JavaWordCount");
        // 创建sparkContext
        JavaSparkContext jsc = new JavaSparkContext(conf);    // java中最关键的两个入口级函数就是,sparkcontext和sparkstreaming
        JavaRDD<String> lines = jsc.textFile(args[0]);     // 指定以后从哪里读取数据
        // 切分压平
        JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public Iterator<String> call(String line) throws Exception {    // 按行读取,将每一行切分成单词
                return Arrays.asList(line.split(" ")).iterator();
            }
        });

        //将单词和一组合在一起
        JavaPairRDD<String, Integer> wordAndOne = words.mapToPair(new PairFunction<String, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(String word) throws Exception {    // 将单词与1组合元组
                return new Tuple2<>(word, 1);
            }
        });

        //聚合
        JavaPairRDD<String, Integer> reduced = wordAndOne.reduceByKey(new Function2<Integer, Integer, Integer>() {    # shuffle类算子,reduceByKey(function,[numTasks]),
            @Override
            public Integer call(Integer v1, Integer v2) throws Exception {    // 将key相同的元组聚合
                return v1 + v2;
            }
        });

        //调换顺序
        JavaPairRDD<Integer, String> swaped = reduced.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
            @Override
            public Tuple2<Integer, String> call(Tuple2<String, Integer> tp) throws Exception {
                //return new Tuple2<>(tp._2, tp._1);
                return tp.swap();
            }
        });

        //排序
        JavaPairRDD<Integer, String> sorted = swaped.sortByKey(false);

        //调整顺序
        JavaPairRDD<String, Integer> result = sorted.mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(Tuple2<Integer, String> tp) throws Exception {
                return tp.swap();
            }
        });

        //将数据保存到hdfs
        result.saveAsTextFile(args[1]);    // 这里没有像mapreduce的waitForCompletion(),也没有

        //释放资源
        jsc.stop();
    }
}

bin/spark-submit --master spark://node-4:7077 --executor-memory 4g --total-executor-cores 12 --class cn.edu360.spark.JavaWordCount    # 任务提交

// 这张图意思性不大,只是构建了一个简单的流程

1、通过spark-submit的方式提交作业,此时应用程序向master发送请求启动Driver程序,Driver程序负责对资源和任务的调度。

     假设deploy_mode采用cluster模式,在spark-submit端会先启动一个clientEndpoint进程,由其请求MasterEndpoint中的RequestSubmitDriver,master接受请求后会给客户端返回一个reply,然后随机调用一个worker,通过其中的LaunchDriver函数来启动driver客户端。

/*    如果你进行spark-submit的机器和worker节点在地理上相近(比如同一个局域网),建议使用client模式,这时driver就在进行spark-submit的线程中。换句话说,进行spark-submit的机器没必要是集群里面的机器,如果你的笔记本安装了Spark环境,就可以提交任务到master节点,这个时候driver就在你的笔记本上运行。这时显然不推荐client模式,因为考虑到网络开销,最好使用cluster模式。使用cluster模式后,Spark就会根据调度算法在集群中选择一个机器作为driver执行的地方。 */

2、driver启动后会与master建立通信,依据任务提交过程中设置的参数来请求资源,每个executor节点需要4g的内存,一共需要12个core来执行任务。另外,我觉得会在这个时候读取spark程序得配置文件,告诉master rdd中对应的文件存储在哪几台机器上,然后master会依据数据存储的位置来启动最优的worker来工作。master会进行资源调度,然后与选定的worker进行rpc通信,让worker启动executor。  // work的选择有什么讲究?需要在数据对应的hdfs上启动吗?如果不是那么数据量很大的时候不就会进行大量的数据传输,大量数据如何存储呢?如果是,那么怎么master通过什么来知道数据对应的节点位置呢?

4、各个被选中的节点启动executor后会与driver建立连接(master让work启动executor的时候会给出driver的位置)。

5、driver端当代码触发action类算子时,会调用DAGScheduler将图进行切分,分成stage,等前面的stage执行完后,后面的stage再执行。一个stage会产生很多业务逻辑相同的task,然后以taskset的形式传递给TaskScheduler,再由其将task序列化,最后传递给指定的executor执行。

6、executor接收到task后,先将task反序列化,然后将task用一个实现了Run接口的实现类包装起来,再丢入线程池中,然后包装类的run方法会被执行,进而调用taks的计算逻辑。上一个stage运行完毕后(类比为map端),会将其结果存入到本地的磁盘文件中,这个时候数据如何分区呢?程序会依据rdd算子中设定的下游的分区数量,将数据分区经过整合后溢出到一个磁盘文件中(SortShuffleManager)。然后下游的stage(reduce端)会通过分区号去上游的每一个task的输出磁盘文件中通过http来拉去属于自己的数据(依据分区索引)。

// stage与task的区别是什么?   解:task是rdd的某一个具体操作,比如map操作,是由每个executor来执行的,而stage中包含了多个task。

// 初始分区的数量由什么决定?    解:对于文件而言,task的数量由分区数量决定,而分区数量默认又是由分片的数量决定的(未指定的情况下)。 所以hdfs读取的时候有多少分片,就要多少task。

 

 

 

SparkShell编程介绍

1、启动spark shell界面

/usr/local/spark-1.5.2-bin-hadoop2.6/bin/spark-shell --master spark://node1.edu360.cn:7077   // 启动spark shell命令行

/*  可以携带的参数:

    --master spark://node1.edu360.cn:7077   指定Master的地址

    --executor-memory 2g   指定每个worker(executor?)可用内存为2G

    --total-executor-cores 2   指定整个集群使用的cup核数为2个

    如果启动spark shell时没有指定master地址,但是也可以正常启动spark shell和执行spark shell中的程序,其实是启动了spark的local模式,该模式仅在本机启动一个进程,没有与集群建立联系。

    在启动spark shell之前,需要先启动spark集群:/usr/local/spark-2.1.0-bin-hadoop2.6/sbin/start-all.sh、hdfs集群:/usr/local/hadoop-2.6.5/sbin/start-dfs.sh。

*/

2、在spark shell界面中编程

> val rdd1 = sc.parallelize(List(5, 6, 4, 7, 3, 8, 2, 9, 1, 10))   //通过并行化生成rdd,也就是自己输入数据

> val rdd2 = rdd1.map(_ * 2).sortBy(x => x, true)    //对rdd1里的每一个元素乘2然后排序

> val rdd3 = rdd2.filter(_ >= 10)    //过滤出大于等于十的元素

> rdd3.collect    //将元素以数组的方式在命令行中显示

> val rdd4 = sc.textFile("hdfs://node1.edu360.cn:9000/words.txt")    // 通过获取hdfs上的数据集来生成rdd

 

 

 

 

Spark基础介绍

1. yarn集群与spark集群的功能对比(spark中的applicationMaster就是通常所说的driver端)

2、三大实时计算框架对比

3、RDD运行流程图

mapreduce中map任务的数量是由分片数量来决定的,而reduce得数量则可以在程序中设定。

那么spark集群中task得数量由谁来决定呢? 解:等于hdfs文件的block数,或者可以说的文件的数量(如果一个块中有多个小文件的话)。如果采用parallelize()的话,初始分区数就由自己设定,例如val rdd1: RDD[Int] = sc.parallelize(1 to 10,4) 。 

4、序列化与反序列化。Java序列化就是指把Java对象转换为字节序列的过程,而Java反序列化就是指把字节序列恢复为Java对象的过程。在spark中,Driver(客户)端会创建一个实例(给其赋予特定的成员变量),然后通过序列化将这个实例发送到Worker节点,worker节点上的executor会将其反序列化后用Runnable接口封装一下,然后丢到线程池中去运行。 

 

 

RDD

1、RDD给我的感觉就类似于一个类,它既包含数据,也包含操作,还有RDD与RDD之间的关系。RDD与mapreduce中的切片很像,都是对数据的抽象,但是RDD中存放的是切片数据的集合,相当于一个文件的所有切片都由RDD来管理,除此之外,RDD还会保存对切片数据的操作,当触发action操作时,就会调用各节点的executor来进行计算处理,其结果可以重新定义一个RDD来存储。RDD算子就是对切片数据的操作函数,每一个算子中的具体的函数实现需要自己定义,其编程范式是函数式编程。

RDD除了以上三个组成部分之外,还有一个Partitioner函数,其不但决定了RDD本身的分片数量(默认是以hdfs块的多少来判断的),也决定了parent RDD Shuffle输出时的分片数量。另外,RDD还有一个列表,用于存储每个Partition的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。

2、 spark常用算子总结

Transformation:

1. map。map的输入变换函数应用于RDD中所有元素,而mapPartitions应用于所有分区。区别于mapPartitions主要在于调用粒度不同。如parallelize(1 to 10, 3),map函数执行10次,而mapPartitions函数执行3次。

2. filter(function)。过滤操作,满足filter内function函数为true的RDD内所有元素组成一个新的数据集。如:filter(a == 1)。

3. flatMap(function)。map是对RDD中元素逐一进行函数操作映射为另外一个RDD,而flatMap操作是将函数应用于RDD之中的每一个元素,将返回的迭代器的所有内容构成新的RDD。而flatMap操作是将函数应用于RDD中每一个元素,将返回的迭代器的所有内容构成RDD。flatMap与map区别在于map为“映射”,而flatMap“先映射,后扁平化”,map对每一次(func)都产生一个元素,返回一个对象,而flatMap多一步就是将所有对象合并为一个对象。

4. mapPartitions(function)。区于foreachPartition(属于Action,且无返回值),而mapPartitions可获取返回值。与map的区别前面已经提到过了,但由于单独运行于RDD的每个分区上(block),所以在一个类型为T的RDD上运行时,(function)必须是Iterator<T> => Iterator<U>类型的方法(入参)。

5. union(otherDataSet)。对于源数据集和其他数据集求并集,不去重。

7. groupByKey([numTasks])。在一个PairRDD或(k,v)RDD上调用,返回一个(k,Iterable<v>)。主要作用是将相同的所有的键值对分组到一个集合序列当中,其顺序是不确定的。groupByKey是把所有的键值对集合都加载到内存中存储计算,若一个键对应值太多,则易导致内存溢出。在此,用之前求并集的union方法,将pair1,pair2变为有相同键值的pair3,而后进行groupByKey。

8. reduceByKey(function,[numTasks])。与groupByKey类似,却有不同。如(a,1), (a,2), (b,1), (b,2)。groupByKey产生中间结果为( (a,1), (a,2) ), ( (b,1), (b,2) )。而reduceByKey为(a,3), (b,3)。reduceByKey主要作用是聚合,groupByKey主要作用是分组。(function对于key值来进行聚合)。

9. sortByKey([ascending], [numTasks])。同样是基于pairRDD的,根据key值来进行排序。ascending升序,默认为true,即升序;numTasks。

10. join(otherDataSet,[numTasks])。加入一个RDD,在一个(k,v)和(k,w)类型的dataSet上调用,返回一个(k,(v,w))的pair dataSet。

Action:    # DAG环的结尾,碰到就将之前的stage依次提交给spark集群运行

1. reduce(function)。reduce将RDD中元素两两传递给输入函数,同时产生一个新值,新值与RDD中下一个元素再被传递给输入函数,直到最后只有一个值为止。(reduce不一定会触发shuffle)

2. collect()。将一个RDD以一个Array数组形式返回其中的所有元素。

3. saveAsTextFile(path)。将dataSet中元素以文本文件的形式写入本地文件系统或者HDFS等。Spark将对每个元素调用toString方法,将数据元素转换为文本文件中的一行记录。若将文件保存到本地文件系统,那么只会保存在executor所在机器的本地目录。

4. foreach(function)。对数据集中每一个元素运行函数function。

3、RDD中cache原理的简单介绍:可以简单的把RDD理解成一个提供了许多操作接口的数据集合,stage中的每一个rdd的运算结果都会存储在本地磁盘上,但是如果某个rdd被频繁的调用,则将其结果存储在内存中可以节省大量的时间(重复计算和磁盘读取)。

4、shuffle类算子总结。

    1、repartition类的操作:比如repartition、repartitionAndSortWithinPartitions、coalesce等。
    2、byKey类的操作:比如reduceByKey、groupByKey、sortByKey等。
    3、join类的操作:比如join、cogroup等。

    重分区:一般会shuffle,因为需要在整个集群中,对之前所有的分区的数据进行随机,均匀的打乱,然后把数据放入下游新的指定数量的分区内。
    byKey类的操作:因为你要对一个key,进行聚合操作,那么肯定要保证集群中,所有节点上的,相同的key,一定是到同一个节点上进行处理。
    join类的操作:两个rdd进行join,就必须将相同join key的数据,shuffle到同一个节点上,然后进行相同key的两个rdd数据的笛卡尔乘积。

 

 

DAG

1、DAG中各个RDD之间存在着依赖关系,换言之,正是由于RDD之间的依赖关系组成了DAG。一个RDD只是描述了数据计算过程中的一个环节,而DAG由一个或多个RDD组成,描述了数据计算过程中的所有环节(过程)。

DAG是有边界的:开始(通过SparkContext创建的RDD),结束(触发Action,调用run Job就是一个完整的DAG就形成了,一旦触发Action就形成了一个完整的DAG)。

一个DAG中可能存在多个stage,即shuffle类算子,但只存在一个action类算子。

一个Spark Application中是有多少个DAG:一个或多个(取决于触发了多少次Action)。

2、shuffle的含义就是洗牌,将数据打散,父RDD的一个分区的数据如果给了子RDD的多个分区(只有存在这种可能),那就是shuffle。shuffle会用网络传输,就是类似mapreduce的reduce从map端接收处理好的数据一样,但是有网络传输的不一定是shuffle。

3、stage的划分依据。stage的划分依赖于宽依赖和窄依赖,宽/窄依赖的解释如下图所示,简单来讲就是一个父RDD的一个分区是否会拆分给子RDD的多个分区,如果是,则就是宽依赖。 而stage的划分就是看有多少个宽依赖,因此spark划分stage的整体思路是:从后往前推,遇到宽依赖就断开,划分为一个stage;遇到窄依赖就将这个RDD加入该stage中。

     宽依赖就可以理解为是shuffle类算子,而action类算子就是DAG环的结尾,遇到action类算子,就将之前的所有的stage依次打包提交spark集群运行。

4、spark在执行过程中可以分为四个过程,包括DAG的构建、stage的划分、任务的调度以及executer对任务的执行。下图前三个部分都是在driver端,最后一个部分才是在spark集群的各个执行节点上的。

5、spark集群上的wordcount运行机制图解。注意,下图这个流程可以划分为两个stage,红线前是一个stage,红线后又是一个stage。

// 引自https://blog.csdn.net/cch19930303/article/details/108687093,侵删

6、task、taskset、stage和job的区别。

Job对应一个DAG,一个Job 中有一到多个Stage,一个作业(应用)可以有多个job。

Stage 是指任务执行阶段 ,一个Stage 对应一个TaskSet。

TaskSet是指保存同一种计算逻辑的多个Task 的集合 ,一个TaskSet 中的Task 计算逻辑都一样 ,不一样的是处理RDD上不同分区中的数据。一个TaskSet 中的Task 的数量取决于Stage 中最后一个RDD 分区的数量 。

Task 其实就是类的实例 ,有属性(从哪里读取数据/读取的是哪个切片的数据) ,有方法(如何计算 / 即数据的计算分析逻辑) 。有多少个分区,就有多少个task,执行函数相同,数据不同(不同的分区数据,不同task中的类成员分区变量值不同)。我的理解,一个stage中会有多个rdd的Transformation,这些算子都会被集中到task中,作为类的成员函数。executor接收到task之后,就可以通过调用其中的类函数对指定分区中的数据进行计算。

Spark的Task分为两种:1)org.apache.spark.scheduler.ShuffleMapTask    2)org.apache.spark.scheduler.ResultTask。ShuffleMapTask可以类比于mapreduce中的map函数,而ResultTask则可以类比于reduce函数。ShuffleMapTask对应的stage阶段称为ShuffleMapStage,而ResultTask对应ResultStage。

 

 

Spark SQL

1、spark sql可以运行在spark shell中,也可以在程序中通过spark sql api调用。

shell代码和api代码

2、dataset与dataframe的区别:DataFrame只是知道字段,但是不知道字段的类型,所以在执行这些操作的时候是没办法在编译的时候检查是否类型失败的,比如你可以对一个String进行减法操作,在执行的时候才报错,而DataSet不仅仅知道字段,而且知道字段类型,所以有更严格的错误检查。就跟JSON对象和类对象之间的类比。dataset数据集只有一列。dataset的特点如下:
    1.一系列分区
    2.每个切片上会有对应的函数
    3.依赖关系
    4.kv类型shuffle也会有分区器
    5.如果读取hdfs中的数据会感知最优位置
    6.会优化执行计划
    7.支持更加智能的数据源

3、DSL就是对sql语句的封装,例如通过personDF.filter(col("age") >= 25).show可以直接获取age大于25的记录信息,而sql语句为spark.sql("select name,age from t_person where age > 25").show。

4、hive on spark。跟hive没太大的关系,就是使用了hive的标准(HQL, 元数据库、UDF、序列化、反序列化机制)

spark sql与hive on spark,使用不同的sql解析器,但是在数据处理层都是采用spark处理的。hive原来的数据处理模块采用mapreduce(1.x),但是在hive2.x中,其将数据处理模块改为了spark,然后在程序中,通过val sqlContext = new HiveContext(sc)语句,使得SparkSQL可以读取HIVE中的数据。而spark sql除了也能在程序中使用外,也可以像hive命令行一样,在spark的命令行中使用。在程序中使用spark sql,其通过对dataframe进行解析,而dataframe中的数据可以来源于很多地方,比如hive中、cvs中,而hive sql只能查询hive表中的数据。

# 在spark命令行中,spark sql 整合hive,将hive的sql写在一个文件中执行(用-f这个参数)
/bigdata/spark-2.2.0-bin-hadoop2.7/bin/spark-sql --master spark://node-4:7077,node-5:7077 --driver-class-path /home/xiaoniu/mysql-connector-java-5.1.7-bin.jar -f hive-sqls.sql

# 在程序开发环境中,整合hive
 <!-- spark如果想整合Hive,必须加入hive的支持 -->
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-hive_2.11</artifactId>
        <version>2.2.0</version>
    </dependency>

    //如果想让hive运行在spark上,一定要开启spark对hive的支持
    val spark = SparkSession.builder()
      .appName("HiveOnSpark")
      .master("local[*]")
      .enableHiveSupport()//启用spark对hive的支持(可以兼容hive的语法了)
      .getOrCreate()

5、DataFrame与RDD的主要区别在于,DataFrame带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。

      DataFrame = RDD[Row] + shcema

 

 

Spark Streaming

流程图,原理介绍

receiver和direct的区别

1、sparkstreaming介绍

Spark Streaming是一个基于Spark Core之上的实时计算框架,可以从很多数据源消费数据并对数据进行处理,在Spark Streaing中有一个最基本的抽象叫DStream(代理),本质上就是一系列连续的RDD,DStream其实就是对RDD的封装DStream可以任务是一个RDD的工厂,该DStream里面生产都是相同业务逻辑的RDD,只不过是RDD里面要读取数据的不相同。

深入理解DStream:它是sparkStreaming中的一个最基本的抽象,代表了一系列连续的数据流,本质上是一系列连续的RDD,你对DStream进行操作,就是对RDD进行操作。DStream每隔一段时间生成一个RDD,你对DStream进行操作,本质上是对里面的对应时间的RDD进行操作。DSteam和DStream之间存在依赖关系,在一个固定的时间点,每个存在依赖关系的DSrteam对应的RDD也存在依赖关系,每个一个固定的时间,其实生产了一个小的DAG,周期性的将生成的小DAG提交到集群中运行。

2、spark streaming 图解

3、DStream图解

4、SparkStreaming的receiver方式和direct方式的区别。 

Direct是边读边处理,类似mapreduce中的迭代器,只不过是以5秒钟作为一个批次。而Receiver则是将数据接收到内存,5秒钟接收一次数据,接收完之后才处理。

5、sparkstreaming使用

package cn.edu360.day9

import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Milliseconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}


object SteamingWordCount {

  def main(args: Array[String]): Unit = {

    // 离线任务是创建SparkContext,现在要实现实时计算,用StreamingContext

    val conf = new SparkConf().setAppName("SteamingWordCount").setMaster("local[2]")
    val sc = new SparkContext(conf)
    //StreamingContext是对SparkContext的包装,包了一层就增加了实时的功能
    //第二个参数是小批次产生的时间间隔
    val ssc = new StreamingContext(sc, Milliseconds(5000))

    //有了StreamingContext,就可以创建SparkStreaming的抽象了DSteam
    //从一个socket端口中读取数据
    //在Linux上用yum安装nc
    //yum install -y nc
    val lines: ReceiverInputDStream[String] = ssc.socketTextStream("192.168.1.207", 8888)
    //对DSteam进行操作,你操作这个抽象(代理,描述),就像操作一个本地的集合一样
    //切分压平
    val words: DStream[String] = lines.flatMap(_.split(" "))
    //单词和1组合在一起
    val wordAndOne: DStream[(String, Int)] = words.map((_, 1))
    //聚合
    val reduced: DStream[(String, Int)] = wordAndOne.reduceByKey(_+_)
    //打印结果(Action)
    reduced.print()

    //启动sparksteaming程序
    ssc.start()
    //等待优雅的退出
    ssc.awaitTermination()
  }
}

6、spark streaming 在项目架构中的应用

 

 

 

问题

1. 如果分布式管理不用spark集群来实现,而是使用yarn集群来管理,则这个时候spark集群的运行模式与没有yarn时的运行模式由什么区别?

2. RDD的分片与列表之间有什么关系?mapreduce中的分片一共有4个属性,不仅指出了分片数据的起始位置与偏移,还指出了分片所在的节点。

3. spark启动时候设置的核数决定了什么?作业的分区数由什么决定?如何改变作业的分区数量?对比spark与mapreduce回答。

    解:决定了运行的资源,如果可以使用的资源少于分区数量,那么有些分区的数据会在第二批中处理,如果资源大于分区数量,那么有些资源就会被浪费。作业的分区数有hdfs的block的数量决定。作业的分区数量无法改变。mapreduce中map的数量由block的数量来决定,reduce的数量可以自己设定。

4. 宽/窄依赖与算子有关系吗?

    解:有关系,shuffle类算子都可以算作是宽依赖。

5. shuffle与宽窄依赖的关系?

    解:有关系,shuffle类算子都可以算作是宽依赖。

6. hive on spark 与 sprak sql的区别?

7. spark sql介绍。

    解:就是sql语法,与mysql差不多,spark sql的运行机制与hive的运行机理差不多,就是将sql转换成spark程序,然后由一系列rdd调用来计算出结果。

8. spark sql与hive on spark的区别是什么?现在只知道这两种都是将sql语句转化成spark程序。

9. task与rdd的区别?

    解:rdd是数据集,task是对数据集的操作。

10. spark是否会依据所要处理的数据块所在的位置,在数据块所在的位置上启动相应的executor?    // 我认为会的

11. 从spark-submit提交任务到driver启动的整个过程?

12. rdd初始分区的数量由什么决定?

    解:等于hdfs文件的block数。在哪几台机器上启动运行task,就是看该机器上是否存在block,优先在数据所在的机器上运行,与mapreduce的想法类似。所以启动的executor数也与block数相同,也等于map数量,一个map处理一个block块。spark的底层实现与mapreduce相似,以后不清楚spark如何运行,就类比mapreduce。

    val rdd1: RDD[Int] = sc.parallelize(1 to 10,4)    // 如果不用hdfs上的数据,采用parallelize()的话,初始分区数就由自己设定。

    spark中没有分区这一说法,分区即是task数。

    Spark进行RDD操作,默认分区数看机器的配置,一般是cores*executors。

    

而 Task被执行的并发度 = Executor数目 * 每个Executor核数。

至于partition的数目:

  • 对于数据读入阶段,例如sc.textFile,输入文件被划分为多少InputSplit就会需要多少初始Task。
  • 在Map阶段partition数目保持不变。
  • 在Reduce阶段,RDD的聚合会触发shuffle操作,聚合后的RDD的partition数目跟具体操作有关,例如repartition操作会聚合成指定分区数,还有一些算子是可配置的。

 

参考链接

1. https://blog.csdn.net/fortuna_i/article/details/81170565    # RDD算子介绍

2. https://blog.csdn.net/Fortuna_i/article/details/80851775    # collect() 算子介绍

3. https://www.cnblogs.com/shenh062326/p/4130973.html    # RDD的底层原理和cache介绍

4. https://blog.csdn.net/weixin_43087634/article/details/84398036    # rdd、dataframe和dataset的区别

5. https://blog.csdn.net/u013939918/article/details/106694018    # shuffle类算子介绍

6. https://blog.csdn.net/tclwh123/article/details/85015264    # 3类算子总结

*7. https://blog.csdn.net/cch19930303/article/details/108687093    # spark内核总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值