Spark学习笔记

文章详细阐述了Spark的弹性分布式数据集(RDD)、执行流程、DAG调度、数据分区与操作、shuffle机制、内存管理和数据缓存策略,以及与MapReduce的比较。此外,还讨论了SparkSQL的join类型和SparkStreaming的数据获取方式,包括Receiver和Direct模式及其优缺点。
摘要由CSDN通过智能技术生成

Spark

RDD(弹性分布式数据集)

特点:逻辑概念。可分区、可依赖,可缓存。

执行流程

执行过程:提交任务后,会首先执行main()函数,来启动SparkSubmit(),客户端向RM申请启动AppM,RM创建AppM读取配置信息,启动Driver进程,初始化SparkContext,并向RM申请启动Executor的资源,RM返回可用资源列表。启动Executor节点后,向Driver端反向注册,注册成功后,启动任务。DAGSchedule根据action算子生成job任务,然后根据shuffle依赖关系,将job划分成多个stage,之后生成多个task,由taskSchedule将task传到Executor执行。

每个action算子触发一个job,每个job可以根据shuffle划分成多个stage,然后每个stage根据分解成和分区数量相同的task数量。

map task个数:通过输入数据大小/每个分片大小。
reduce task个数:一般通过设置partition数量简介设置。

逻辑处理流程(输入输出、中间数据、依赖关系)

分区方法:水平划分、HashPartitioner、RangePartitioner。
数据操作:
transformation操作:

map(func)、
flatmap(func)、
sample(withReplacement,fraction,seed)、
groupByKey([numPartitions])、
reduceByKey(func,[numPartitions])、
foldByKey(zeroValue)(func)、
aggregateByKey(zeroValue)(seqOp,combOp,[numPartitions])、
combineByKey(createCombiner,mergeValue,mergeCombiners,[numPartitions])、
join(otherDataset,[numPartitions])、
coalesce(numPartitions)

join的三种实现方式:sort merge join、broadcast join、hash join。
buildlter小的时候,可以用broadcast join;
通常情况下可以用:sort merge join;
hash join使用条件:总大小大于(不适合使用)broadcast join,各分区大小小于broadcast大小,streamlter是buildlter的三倍。

在spark sql查询优化阶段,spark会自动将大表设为左表,即streamIter,将小表设为右表,即buildIter。
一般让大表作为streamlter表,即left outer join 让左表为大表。
full outer join仅采用sort merge join实现,左边和右表既要作为streamIter,又要作为buildIter。

left semi join是以左表为准,在右表中查找匹配的记录,如果查找成功,则仅返回左边的记录,否则返回null。
left anti join与left semi join相反,是以左表为准,在右表中查找匹配的记录,如果查找成功,则返回null,否则仅返回左边的记录。

action操作:

count()、
collect()、
foreach(func)、
fold(zeroValue)(func)、
reduce(func)、
aggregate(zeroValue)(seqOp,combOp,[numPartitions])、
treeAggregate(zeroValue)(seqOp,combOp,depth)、
treeReduce(func,depth)、
take(num)、
saveAsTextFile()

MapReduce和Spark的优缺点:

  • Spark更有通用性:将输入输出、中间数据抽象为一个RDD,更加灵活。可定义数据依赖关系连接中间数据,使用DAG图来组合输出处理操作。
  • Spark更有易用性:数据操作很多,更容易实现复杂流程,可并行化。

Spark缺点:

  1. 单项操作,中间数据不可修改;
  2. 粗粒度,面向分区。

一个基于进程,一个基于线程。

物理执行计划(划分stask执行)

  1. 根据action()操作划分job。
  2. 根据shuffleDependency依赖关系,将job划分为执行阶段(stage)。
  3. 根据最后生成RDD的分区个数生成多个计算任务(task)。

同一个stage中的每个task可并行执行。

shuffle机制

shuffle Write:聚合----排序----分区。

  1. 不需要聚合和排序:spark根据partitionId,将record依次输出到不同的buffer中。每当buffer填满就将record溢写到磁盘上的分区文件中。BypassMergeSortShuffleWrite。适合分区个数小于200的情况。
  2. 不需要聚合,需要排序:采用Array来存放record,存不下,先扩容,还存不下,排序后spill到磁盘上,等map输出完后,再全局排序。适用于分区个数很大的情况。增加了排序的计算时间。
  3. 需要聚合:采用类似HashMap的结构来对record聚合,存不下,先扩容两倍,还存不下,排序后spill到磁盘上,等map输出完后,再全局聚合。使用聚合的情况。

shuffle Read:聚合----排序。

  1. 不需要聚合和排序:从map task获取数据,将记录输出到buffer中,下一个操作直接从buffer中获取。
  2. 不需要聚合,需要排序: 从map task获取数据,将数据存放在类Array中,存放不下,spill到磁盘进行,最后进行全局排序。
  3. 需要聚合:采用类似HashMap的结构来对record聚合,存不下,先扩容两倍,还存不下,排序后spill到磁盘上。如果需要排序,建立一个Array结构,排序。

PartitionedPairBuffer:用于map和reduce端的排序。
PartitionedAppendOnlyMap:用于map端聚合排序。
ExternalAppendOnlyMap:用于reduce端聚合排序。

shuffle类型

hashShuffle:每个MT会根据每个RT生成对应个数的磁盘文件,个数多,效率低
优化之后的hashShuffle:每个Executor根据每个RT生成对应个数的磁盘文件,个数相对少。
sortHashShuffle:每个Executor生成一个磁盘文件和对应的索引,个数少,效率高。
bypass:需要满足两个条件:1.不是聚合类的算子;2.MT个数小于默认的bypass个数(200)。

MapReduce和Spark的shuffle比较

MapReduce的shuffle:map stage和reduce stage。

  • map stage:读取record,并输出新的record,输出到一个环形缓冲区100M,超过80M,将缓冲区中的record按照key排序后输出到磁盘上,之后如果需要聚合,需要等所有recordspill到磁盘后,使用combine进行全局聚合。
  • reduce stage:通过网络获取map stage数据,然后放在内存中,放不下就先聚合排序,spill到磁盘,获取所有文件后,再启动一个reduce阶段进行全局聚合。

优点:阶段分明;内存消耗确定;支持spill磁盘。
缺点:只按key进行排序;不能在线聚合;产生临时文件过多。

Spark:可以按partitionId排序、key排序;使用hashmap可以在线聚合;可以合并分区文件。

数据缓存机制

缓存:对某些需要多次使用的数据进行缓存,目的是为了加速计算。
3个条件:

  1. 会被重复使用的数据
  2. 数据不易过大
  3. 非重复缓存的数据

cache():是lazy操作,不会立即执行,生成job后才会执行写到内存,cache直将数据写到内存,如果想使用别的存储方式,可以使用persist(方式)。缓存数据只能在job间共享,应用之间不能共享。

缓存级别:

缓存级别存储位置序列化存储内存不足放磁盘
NONE不存储
MEMORY_ONLY内存
MEMORY_ONLY _SER内存序列化
MEMORY_AND_DISK内存+磁盘
MEMORY_AND_DISK_SER内存+磁盘序列化
DISK_ONLY磁盘序列化
OFF_HEAP对外内存序列化
MEMORY_ONLY_2多台机器内存
MEMORY_ONLY _SER_2多台机器内存序列化
MEMORY_AND_DISK_2多台机器内存+磁盘
MEMORY_AND_DISK_SER_2多台机器内存+磁盘序列化
DISK_ONLY_2多台机器磁盘序列化

缓存数据的替换和回收:

  1. 自动缓存替换:LRU最久未使用的缓存被替换。
  2. 用户主从回收缓存数据:umpersis()操作。

错误容忍机制

错误容忍机制:在应用执行失败时能够自动恢复应用执行,并且执行结果与正常执行时得到的结果一致。

方法:

  1. 重新执行计算任务来容忍错误
  2. 通过采用checkpoint机制,对数据进行持久化。

重新计算条件:

  1. task输入数据与之前是一致的
  2. task的计算逻辑需要满足确定性(输入确定,输出确定)
  3. task的计算逻辑需要满足幂等性(对同样数据进行多次运算,结果一致)
    延时删除:上游stage的shuffle write的结果写入本地磁盘,只有当job完成后,才删除shuffle write写入磁盘的数据。

使用lineage的数据溯源方法来对数据重新计算,记录上游数据和上游方法。

checkpoint机制:将计算过程中的数据进行持久化。对计算耗时高的数据进行持久化。对于迭代性job需要每隔几个job就对一写中间数据进行checkpoint。

checkpoint:等到job执行结束后,再重新启动该job计算一遍,对其中需要checkpoint的RDD进行持久化。这样可能会增加开销,可以先对持久化的数据进行缓存,然后将缓存的数据持久化,不需要重新计算,从而提高效率。

CheckPoint与数据缓存的区别

  1. 目的不同:数据缓存的目的是加速,checkpoint的目的是job运行失败后能够快速恢复。
  2. 存储性质和位置不同:数据缓存主要使用内存,checkpoint使用分布式文件系统。
  3. 写入速度和规则不同:数据缓存速度快,可在job运行时进行缓存,checkpoint在job结束后,重新执行job。
  4. 对lineage的影响不同:数据缓存对lineage没有影响,chechpoint会切断RDD的lineage。
  5. 应用场景不同:数据缓存使用于多次读取,占用空间不大的数据,checkpoint适用于数据依赖关系复杂,重新计算代价高的数据。

内存管理机制

内存消耗来源:用户代码、shuffle机制中产生的中间数据、缓存数据。

堆内内存和堆外内存:堆内内存受JVM的管理,堆外内存受操作系统的管理。
堆内内存:执行内存(shuffle)、缓存内存、用户内存、预留内存。
堆外内存:执行内存、缓存内存。

Spark内存模型:

  1. 静态内存管理模型:数据缓存空间60%,框架执行空间20%,用户代码空间20%。
  2. 统一内存管理模型:数据缓存和框架执行共享一个大空间(60%),动态调整(有上下界),其他内存(40%),用户代码设置固定值。(执行内存被存储内存占用,存储内存可以转存到磁盘,但是存储内存被执行内存占用后,执行内存不能归还;简单来说,执行内存是老大)

task占用内存大小=[1/2N,1/N] * Execution Memory。

数据缓存空间管理:RDD缓存数据(RDD partition)、广播数据(Broadcase data),task计算结果(TaskResult)

Spark Streaming

SparkStreaming基于kafka获取数据的方式,主要有俩种,即Receiver和Direct。

基于Receiver的方式,是SparkStreaming给我们提供了kafka访问的高层api的封装;这种方式可能会因为底层的失败而丢失数据,如果要启用高可靠机制,让数据零丢失,就必须启用Spark Streaming的预写日志机制(Write Ahead Log,WAL),该机制会同步地将接收到的Kafka数据写入分布式文件系统(比如HDFS)上的预写日志中,所以当底层节点出现了失败,可以通过WAL中的数据进行恢复,但是效率会下降
基于Direct的方式,就是直接访问,在SparkSteaming中直接去操作kafka中的数据,不需要前面的高层api的封装。而Direct的方式,可以对kafka进行更好的控制!同时性能也更好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值