【Spark】Spark Core学习笔记

Spark Core

Spark Core实现了Spark的基本功能,包括:任务调度,内存管理,错误回复,与存储系统交互等模块。其中包括三大数据结构:

  • RDD:弹性分布式数据集
  • 累加器:分布式共享只写变量
  • 广播变量:分布式共享只读变量

RDD

RDD特性- - 源码

RDD.scala文件,可以从makeRDD() -> RDD -> RDD.scala找到

 * Internally, each RDD is characterized by five main properties:
 *
 *  - 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可以类比Java的I/O

Java I/O

在这里插入图片描述

  • 读取文件数据的核心代码是FileInputStream()
  • 将字节流Stream转换为字符流Reader
  • 增加Buffer缓冲区

整个过程体现装饰者设计模式,即外面包裹的类只是对核心功能FileInputStream()的扩展

类比Java I/O - - RDD

//WordCount,进入方法可以查看到相应的RDD
//建立和Spark框架的连接
valsparkConf=newSparkConf().setMaster("local").setAppName("WordCount")
valsc=newSparkContext(sparkConf)
//执行业务操作
//此时.var后默认是没有RDD的,且RDD并不影响结果
valline=sc.textFile("data")
valwords=line.flatMap(_.split(""))
valwordToOne=words.map(
	word=>(word,1)
)
//相同的key的数据,可以对value进行聚合
valwordToCount=wordToOne.reduceByKey(_+_)
valarray=wordToCount.collect()
array.foreach(println)

在这里插入图片描述
RDD与I/O流的区别于联系

  1. RDD的数据处理方式类似于IO流,也有装饰者设计模式
  2. RDD的数据只有在调用collect方法时,才会真正执行业务逻辑操作,之前的封装时功能的扩展
  3. RDD是不保存数据的,但是IO可以临时缓存一部分数据,通过分区来分解数据

RDD分区与并行度

RDD分区与分区数据分配源码解析
Spark 可以将一个作业进行分区,每个分区称为一个子任务,发送给 Executor 节点并行计算,而能够并行计算的任务数量我们称之为并行度

  • 切分的任务数可以在构建RDD时指定
  • 并行执行的任务 ≠ 切分的任务数。可以并行执行的任务数前提是有相应的Executor进行计算
  • 默认并行度
    spark在默认情况下,从配置对象中获取配置参数:spark.default.paralelism
    如果获取不到,那么使用totalCores属性,这个属性取值为当前运行环境的最大可用核心数,个人计算机是4核的
override def defaultParallelism():Int=scheduler.conf.getInt("spark.default.parallelism",totalCores)//默认值为tatalCores
  • 分区数据的分配 - - 可以查看源码

RDD算子

算子就是方法,只是为了和scala的方法在名称上做区分

  • 转换算子:对旧的RDD进行功能的补充和包装,转换为新的RDD
  • 行动算子:触发任务调度和作业执行,涉及到提交作业
    转换算子返回的是RDD,行动算子返回的是值或者对象

shuffle

  • shuffle需要落盘,使用磁盘I/O,影响性能
  • 一些转换算子存在shuffle,如groupbyKey和reduceByKey均会用到shuffle,但reduceByKey支持分区内预聚合,性能优于groupByKey

RDD序列化

RDD序列化源码解析
序列化的目的:是为了保证数据在Driver和Executor中间通过网络进行传输

从计算的角度, 算子以外的代码都是在Driver 端执行, 算子里面的代码都是在 Executor 端执行。会导致算子内经常会用到算子外的数据,因此形成了闭包的效果。在调用算子外的数据时,数据需要在Driver和Executor中间通过网络进行传输,因此需要序列化
如果使用的算子外的数据无法序列化,就意味着无法传值给Executor 端执行,就会发生错误,所以需要在执行任务计算前,检测闭包内的对象是否可以进行序列化,这个操作我们称之为闭包检测

RDD依赖

RDD依赖源码解析

  • 依赖:当前RDD需要用到旧RDD,则当前RDD依赖于旧RDD
  • 血缘关系:多个连续RDD的依赖关系
  • 容错性:每个RDD会记录之前的所有血缘关系,当该RDD 的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区
  • OneToOne依赖(窄依赖):新的RDD的一个分区的数据依赖于旧的RDD一个分区的数据,称为OneToOne依赖。比喻为独生子女,东西都给这一个孩子
  • Shuffle依赖(宽依赖):新的RDD的一个分区的数据依赖于旧的RDD多个分区的数据,比喻为多生
    阶段:一个阶段表示所有任务已经结束,此时数据才完整,才可以进入下一个阶段。阶段与shuffle有关,需要等待数据完整之后才会进行shuffle打乱,此时等待即为阶段

RDD持久化

RDD中不存储数据,当代码中未做持久化,且想要重用之前的代码时,用的不是RDD中已经处理好的数据,而是根据RDD通过血缘关系存储的对象和依赖重新执行一遍整个流程
目的:
1. 保证数据的重用
2. 提高执行效率,如果之前代码执行时间很长时可以考虑用持久化提高效率

在这里插入图片描述
Q:cache,persist,checkpoint均能持久化数据,他们的区别是什么

  • cache:将数据临时存储在内存中进行数据重用。会在血缘关系中添加新的依赖。一旦出现问题,可以重头读取数据
  • persist:将数据临时存储在磁盘文件中进行数据重用。涉及到磁盘I/O,性能较低,但是数据安全;如果作业执行完毕,临时保存的数据文件就会丢失
  • checkpoint:将数据长久地保存在磁盘文件中进行数据重用。涉及到磁盘I/O,性能较低,但是数据安全。为了保证数据安全,一般情况下回独立执行作业;为了能够提高效率,一般情况下是需要和cache联合使用;执行过程中,会切断血缘关系,重新建立新的血缘关系(checkpoint等同于改变数据源,改变数据源是指数据获取的位置不同,checkpoint是从检查点获取数据,正常则是通过最初安源文件获取的数据)

累加器

  • 出现原因:闭包问题,Driver和Executor无法共享数据
  • Acc累加器类似全局变量
  • 可以自定义累加器,需要继承重写相应的函数
  • 分布式共享只写变量

广播变量

  • Driver把数据是传给Executor的Task,当存在多个Task会出现数据冗余的情况
  • 解决不同Task中存放冗余数据的情况
  • 广播变量允许不同Task访问
  • 广播变量不允许修改
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值