关于Spark RDD 的认识

一、基本认识

RDD 是Spark大数据计算引擎中,抽象的一种数据结构。

RDD(Resilient Distributed Dataset),中文意思是弹性分布式数据集,它是Spark中的基本抽象。在Spark源码中,有下面的注释:

 

 

RDD 有五个主要的属性:

  • A list of partitions (分区列表)
  • A function for computing each split (分区计算函数) 相同的计算逻辑应用在不同的分区中
  • A list of dependencies on other RDDs (多个RDD之间存在依赖关系)
  • Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned) (对键值对类型的数据进行分区)
  • Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file) (首选位置,计算数据的位置)
二、RDD的执行原理
 
    类似于IO处理,体现了装饰者设计模式。
 
    从计算的角度来看,计算过程受两个因素的影响:计算资源和计算逻辑。执行计算的过程就是将计算资源和计算逻辑进行一定的整合。
    
    spark在执行计算的过程中,会先向集群申请资源,然后把程序的处理逻辑分成一个个的计算任务,然后把任务发到已经分配资源的计算节点上。按照指定的计算模型进行数据计算。
    
    RDD是spark用于数据处理的核心模型。Yarn环境中,RDD的执行原理如下所示:
 
  • 启动Yarn集群资源
    
           
 
  • spark申请资源,创建调度节点和计算节点
          
 
  • 根据需求,spark把计算逻辑,根据分区,划分成不同的任务
          
 
 
  • 调度节点把任务根据计算节点的状态,发送到对应的计算节点上进行计算
          
 
三、在代码中使用RDD
 
1、创建RDD
从集合(内存)、外部文件、其它RDD中创建RDD,代码如下:
 1 import org.apache.spark.rdd.RDD
 2 import org.apache.spark.{SparkConf, SparkContext}
 3 
 4 object Spark01RddCreate {
 5   def main(args: Array[String]): Unit = {
 6     System.setProperty("hadoop.home.dir", "C:\\Hadoop\\")
 7     val sparkConf = new SparkConf().setMaster("local[*]").setAppName("spark01rddmemory")
 8     val sc = new SparkContext(sparkConf)
 9 
10     // TODO: Spark 从内存中创建RDD
11     val list = List(1, 2, 3, 4)
12     val rdd1 = sc.parallelize(list)
13     val rdd2 = sc.makeRDD(list)
14     rdd1.collect().foreach(println)
15     rdd2.collect().foreach(println)
16 
17     // TODO: Spark 从外部文件中创建RDD
18     val sc_text: RDD[String] = sc.textFile("G:\\SNBRecommendSys\\recommender\\DataLoader\\src\\main\\input_data")
19     System.out.println("从外部文件中创建RDD:\n")
20     sc_text.collect().foreach(println)
21 
22     // TODO: Spark 从其他RDD创建RDD
23     val flatRDD = sc_text.flatMap(line => {
24       line.split(" ")
25     })
26     System.out.println("从其他RDD创建RDD:\n")
27     flatRDD.collect().foreach(println)
28 
29     sc.stop()
30   }
31 }

 

2、关于RDD并行度的理解

Spark将一个作业切分为多个任务后,会发送给Excutor节点并行计算,能够并行计算的任务数量就是并行度。计算的任务数量可以在创建RDD的时候去指定。
RDD中,分区的数量就是RDD的并行度,设置并行度就是设置分区的数量。
 
下面代码中,我们可以看到设置并行度,就是在创建RDD的时候,传入的第二个参数值
 1 import org.apache.spark.{SparkConf, SparkContext}
 2 
 3 object Spark02RddParallelizeSet {
 4   def main(args: Array[String]): Unit = {
 5     System.setProperty("hadoop.home.dir", "C:\\Hadoop\\")
 6     val spark = new SparkConf().setMaster("local[*]").setAppName("RddParallelizeSet")
 7     val context = new SparkContext(spark)
 8 
 9     val list = List(1, 2, 3, 4, 5)
10 
11     // TODO: 从内存创建RDD,并且设置并行执行的任务数量
12     // numSlices: Int = defaultParallelism
13     val memoryRDD = context.makeRDD(list, 4)
14     memoryRDD.collect().foreach(println)
15 
16     // TODO: 结束
17     context.stop()
18   }
19 }

 

我们在一层层进入Spark源码,最终可以查看到关于RDD并行度的相关信息:

我们可以在这个实现方法里看到 scheduler.conf.getInt(参数一,参数二),参数一是spark配置文件里的一个配置项,参数二的意思是本地机器的cpu核数。调度程序是从spark的配置文件里读取了 spark.default.parallelism 这个配置。如果没有读取到这个配置的话,则并行度设置将会与本地机器的cpu核数一样。

现在回到我们自己写的程序里,在创建spark配置实例的时候,我们其实已经在设置要用多少个本地机器的核数了:

setMaster() 里面的 local[*],代表的含义是本地机器cpu有多少核,在调度的时候就用到多少核。当然我们也可以设置其它数字,如果你想这样做的话。现在,我们大致可以理解设置并行度是怎么一回事了。
 
最后,源码是个好东西,多去看优秀的源码,很多不清楚的地方都能够迎刃而解。
加油,共勉!
 
posted @ 2020-08-19 15:36  GetMyCode  阅读(265)  评论(0编辑  收藏  举报