SPARK-CORE&RDD(概述)

SPARK-CORE&RDD(概述)

前言

  • RDD
  • 共享变量

每个Spark应用都包含一个Driver程序运行在用户的主程序中,而且Spark应用可以通过一个Spark集群并行执行多个操作,Spark在数据层面提供了一个非常重要的抽象RDDresilient distributed dataset)即弹性分布式数据集,RDD是一个能够并行执行,并切存在与不同节点上的elements的集合,RDD可以从Hadoop文件系统、scala集合等不同的数据源进行创建,主要创建方式有:

sc.makeRDD(data)

sc.parallelize(data)

sc.textfile()sc.wholeTextFile() …

df.rdd

ds.rdd

开发人员可以调用Spark去持久化一个RDD在内存中,这样能保证RDD的复用性,减少non-aged血缘关系链上的重复计算,同时RDD可以自动从错误中进行恢复;

另一个重要的抽象是共享变量,因为spark中闭包的特殊性,共享变量特别重要在默认情况下,当spark将一个函数作为一个tasks的集合在不同的nodes中并行执行,每个task都管理着当前的函数所需要的变量备份在内存中,有时一个变量需要在tasks中,或者在tasks&driver中进行共享传递

spark中的共享变量有2种:

Broadcast variables 广播变

Accumulator 累加器

广播变量:能够被缓存在不同node的JVM内存中,可以被节点上的executor的tasks共享

累加器:只读变量,由driver端生成,可以在executor的tasks中进行count\sum操作

RDD创建

    //1.从scala集合创建一个RDD
    val ints = Seq(1, 2, 3, 4, 5)
    var rdd: RDD[Int] = sc.makeRDD(ints)
    rdd = sc.parallelize(ints)
    val i: Int = rdd.reduce(_ + _)
    println(i)

    //2.从文件读取创建RDD,spark的所有文件读取方法都支持:可以读取目录、文件、以相同后缀结尾的文件集合

    //2.1 textFile()
    sc.textFile("/*.txt")
    sc.textFile("/hello.txt")
    sc.textFile("/data")
    //2.2 wholeTextFiles()
    sc.wholeTextFiles("/")
    //2.3 sequenceFile[K,V](),其中KV必须是Hadoop中的序列化类型,IntWriteAble or Text......
    sc.sequenceFile[Text,IntWritable]("/")
    //2.4 objectFile()
    sc.objectFile("")

RDD算子

RDD支持2中类型的操作:

1、transform 从RDD=>RDD

2、action 从RDD=>集合

例如:

map()就是一种转换算子而reduce就是一个action算子,触发计算执行操作,将值返回给Driver端

spark中的所有的transform算子都是lazy执行的,只有遇见action算,action算子之前的算子才会被划分为stage->taskset=>task manager->tasks根据血缘关系依次执行,假如血缘关系特别长,可能有些算子会被重复计算很多次,所以我们可以通过cache\persist将RDD持久化到内存或者磁盘中,以便下次可以更快的进行访问,无需重新计算。

Spark closure闭包

首先我们先了解scala中的闭包是什么:

//假如一个变量,在其他方法或者【匿名】函数中被引用,那么这个方法以及该变量就形成了一个闭包
var sum = 0;
def a():Unit={
  sum+=1
}

localMode&clusterMode

下面的rdd算子也形成了一个闭包,我们来分析一下本地模式与集群模式下的执行差异

var counter = 0 
var rdd = sc.parallelize(data)

// Wrong: Don't do this!!
rdd.foreach(x => counter += x)

println("Counter value: " + counter) 

在Spark程序中,根据action算子触发job提交,当执行job的时候,Spark将执行中的RDD算子切分成多个tasks,交给executor进行执行,在执行的过程中,Spark会计算task的闭包,但是闭包必须对executor是可见的才能对RDD进行计算,这个closure被序列化分发到每个executor上,但是closure中的变量counter只是相当于一个拷贝副本,因此被foreach()算子引用时,它已经不再是driver端的那个counter,因为driver端现在还保留着counter但是对于executor端是不可见的,所以当打印counter的时候 counter仍然 = 0,因为所有关于counter的操作都只是在序列化的闭包中对counter的copies进行操作。

localmode

在本地模式下,有些特殊情况下executor的执行内存与driver的内存属于同一个JVM(client),这时候闭包的操作才有可能会直接引用driver端的变量,并且可以update该counter的值

clustermode

在分布式集群模式下,driver端与executor是跨节点的,driver、executor的启动与分配都是通过集群管理器管理的例如yarn,所以这种情况下executor的操作只会修改counter的副本值,而driver端的值保持不动

NOTE所以在分布式集群模式下,建议使用Accumulator来实现累加功能,所以需要被共享的数据类型必须支持序列化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值