Spark
1.spark中的RDD
RDD(Resilient Distributed Dataset)叫做分布式数据集,是spark中最基本的数据抽象,它代表一个不可变,可分区,里面的元素可以并行计算的集合
RDD被表示为对象,通过对象上的方法调用来对RDD进行转换。经过一系列的transformations定义RDD之后,就可以调用actions触发RDD的计算,action可以是向应用程序返回结果(count, collect等),或者是向存储系统保存数据(saveAsTextFile等)。在Spark中,只有遇到action,才会执行RDD的计算(即延迟计算),这样在运行时可以通过管道的方式传输多个转换。
2.coalesce和repartition的区别
coalesce重新分区,可以选择是否进行shuffle过程。由参数shuffle: Boolean = false/true决定。
repartition实际上是调用的coalesce,默认是进行shuffle的。
减少分区允许不进行shuffle过程,但是增大分区需要。
所以coalesce可以在不进行shuffle的情况下减少分区,增大分区需要指定第二个参数为true
减少分区的应用场景:例如通过filter之后,有些分区数据量比较少,通过减少分区,防止数据倾斜
增大分区的应用场景:分区内数据量太大,通过增加分区提高并行度
3.spark中的宽窄依赖
窄依赖
父RDD和子RDD partition之间的关系是一对一的。或者父RDD一个partition只对应一个子RDD的partition情况下的父RDD和子RDD partition关系是多对一的。不会有shuffle的产生。父RDD的一个分区去到子RDD的一个分区。
宽依赖
RDD与子RDD partition之间的关系是一对多。会有shuffle的产生。父RDD的一个分区的数据去到子RDD的不同分区里面。
4.spark中如何划分stage
Spark任务会根据RDD之间的依赖关系,形成一个DAG有向无环图,DAG会提交给DAGScheduler,DAGScheduler会把DAG划分相互依赖的多个stage,划分依据就是宽窄依赖,遇到宽依赖就划分stage,每个stage包含一个或多个task,然后将这些task以taskSet的形式提交给TaskScheduler运行,stage是由一组并行的task组成
注意:
park程序中可以因为不同的action触发众多的job,一个程序中可以有很多的job,每一个job是由一个或者多个stage构成的,后面的stage依赖于前面的stage,也就是说只有前面依赖的stage计算完毕后,后面的stage才会运行;
stage 的划分标准就是宽依赖:何时产生宽依赖就会产生一个新的stage,例如reduceByKey,groupByKey,join的算子,会导致宽依赖的产生;
5.DAG
DAG,有向无环图,说白了,就是一个由顶点和有方向性的边构成的图中,从任意一个顶点出发,并且不会回到原点,它为每个spark job计算出有多少个stage任务阶段,通常根据shuffle来划分stage,如reduceByKey,groupByKey等涉及到shuffle的transformation就会产生新的stage ,然后将每个stage划分为具体的一组任务,以TaskSets的形式提交给底层的任务调度模块来执行,其中不同stage之前的RDD为宽依赖关系,TaskScheduler任务调度模块负责具体启动任务,监控和汇报任务运行情况。
6.Job的生成
在编写的一个程序中只要有一个行动算子的出现例如:collect ,就会生成一个job。然后向DAGScheduler提交job,如果driver程序后面还有别的action,那么其他action也会对应生成相应的job,所以,driver端有多少action就会提交多少job,这可能就是为什么spark将driver程序称为application而不是job 的原因。每一个job可能会包含一个或者多个stage,最后一个stage生成result,在提交job 的过程中,DAGScheduler会首先从后往前划分stage,划分的标准就是宽依赖,一旦遇到宽依赖就划分,然后先提交没有父阶段的stage,并在提交过程中,计算该stage的task数目以及类型,并提交具体的task,在这些无父阶段的stage提交完之后,依赖该stage 的stage才会提交
7.RDD缓存
Spark可以使用 persist 和 cache 方法将任意 RDD 缓存到内存、磁盘文件系统中。缓存是容错的,如果一个 RDD 分片丢失,可以通过构建它的 transformation自动重构。被缓存的 RDD 被使用的时,存取速度会被大大加速。一般的executor内存60%做 cache, 剩下的40%做task。
Spark中,RDD类可以使用cache() 和 persist() 方法来缓存。cache()是persist()的特例,将该RDD缓存到内存中。而persist可以指定一个StorageLevel。StorageLevel的列表可以在StorageLevel 伴生单例对象中找到。
8.spark的有几种部署模式
8.1.本地模式
Spark不一定非要跑在hadoop集群,可以在本地,起多个线程的方式来指定。将Spark应用以多线程的方式直接运行在本地,一般都是为了方便调试,本地模式分三类
local:只启动一个executor
local[k]:启动k个executor
local:启动跟cpu数目相同的 executor
8.2standalone模式
分布式部署集群, 自带完整的服务,资源管理和任务监控是Spark自己监控,这个模式也是其他模式的基础
8.3Spark on yarn模式
分布式部署集群,资源和任务监控交给yarn管理,但是目前仅支持粗粒度资源分配方式,包含cluster和client运行模式,cluster适合生产,driver运行在集群子节点,具有容错功能,client适合调试,dirver运行在客户端
9.spark中worker 的主要工作
管理当前节点内存,CPU的使用情况,接受master发送过来的资源指令,通过executorRunner启动程序分配任务,worker就类似于包工头,管理分配新进程,做计算的服务,相当于process服务,需要注意的是
-
worker会不会汇报当前信息给master?worker心跳给master主要只有workid,不会以心跳的方式发送资源信息给master,这样master就知道worker是否存活,只有故障的时候才会发送资源信息;
-
worker不会运行代码,具体运行的是executor,可以运行具体application斜的业务逻辑代码,操作代码的节点,不会去运行代码。
10.hadoop和spark的shuffle相同和差异
10.1 同
都是将 mapper(Spark 里是 ShuffleMapTask)的输出进行 partition,不同的 partition 送到不同的 reducer(Spark 里 reducer 可能是下一个 stage 里的 ShuffleMapTask,也可能是 ResultTask)。Reducer 以内存作缓冲区,边 shuffle 边 aggregate 数据,等到数据 aggregate 好以后进行 reduce() (Spark 里可能是后续的一系列操作)。
10.2 异
-
Hadoop的有一个Map完成,Reduce便可以去拉取数据了,不必等到所有Map任务完成,而Spark的必须等到父stage完成,也就是父stage的map操作全部完成才能去拉取数据。
-
Hadoop的Reduce要等到拉取完全部数据,才将数据传入reduce函数进行聚合,而spark是一边拉取一边聚合。
11.spark组件
-
master:管理集群和节点,不参与计算。
-
worker:计算节点,进程本身不参与计算,和master汇报。
-
Driver:运行程序的main方法,创建spark context对象。
-
spark context:控制整个application的生命周期,包括dagsheduler和task scheduler等组件。
-
client:用户提交程序的入口。
12.spark工作机制
spark-submit
提交代码,执行new SparkContext()
,在 SparkContext 里构造DAGScheduler
和TaskScheduler
。- TaskScheduler 会通过后台的一个进程,连接 Master,向 Master 注册 Application。
- Master 接收到 Application 请求后,会使用相应的资源调度算法,在 Worker 上为这个 Application 启动多个 Executer。
- Executor 启动后,会自己反向注册到 TaskScheduler 中。 所有 Executor 都注册到 Driver 上之后,SparkContext 结束初始化,接下来往下执行我们自己的代码。
- 每执行到一个 Action,就会创建一个 Job。Job 会提交给 DAGScheduler。
- DAGScheduler 会将 Job划分为多个 stage,然后每个 stage 创建一个 TaskSet。
- TaskScheduler 会把每一个 TaskSet 里的 Task,提交到 Executor 上执行。
- Executor 上有线程池,每接收到一个 Task,就用 TaskRunner 封装,然后从线程池里取出一个线程执行这个 task。(TaskRunner 将我们编写的代码,拷贝,反序列化,执行 Task,每个 Task 执行 RDD 里的一个 partition)
13.collect是什么
driver通过collect把集群中各个节点的内容收集过来汇总成结果,collect返回结果是Array类型的,collect把各个节点上的数据抓过来,抓过来数据是Array型,collect对Array抓过来的结果进行合并,合并后Array中只有一个元素,是tuple类型(KV类型的)的。
14.map与flatMap的区别
map:对RDD每个元素转换,文件中的每一行数据返回一个数组对象
flatMap:对RDD每个元素转换,然后再扁平化将所有的对象合并为一个对象,文件中的所有行数据仅返回一个数组对象,会抛弃值为null的值
15.Spark 中算子的使用
在我们的开发过程中,能避免则尽可能避免使用 reduceByKey、join、distinct、repartition 等会进行 shuffle 的算子,尽量使用 map 类的非 shuffle 算子。这样的话,没有 shuffle 操作或者仅有较少 shuffle 操作的 Spark 作业,可以大大减少性能开销。
16.Spark 优点
-
更高的性能。因为数据被加载到集群主机的分布式内存中。数据可以被快速的转换迭代,并缓存用以后续的频繁访问需求。在数据全部加载到内存的情况下,Spark可以比Hadoop快100倍,在内存不够存放所有数据的情况下快hadoop10倍。
-
通过建立在Java,Scala,Python,SQL(应对交互式查询)的标准API以方便各行各业使用,同时还含有大量开箱即用的机器学习库。
-
与现有Hadoop 1和2.x(YARN)生态兼容,因此机构可以无缝迁移。
-
方便下载和安装。方便的shell(REPL: Read-Eval-Print-Loop)可以对API进行交互式的学习。
-
借助高等级的架构提高生产力,从而可以讲精力放到计算上。
17.MapReduce和Spark的差异
原理上:
-
MapReduce:基于磁盘的大数据批量处理系统
-
Spark:基于RDD(弹性分布式数据集)数据处理,显示将RDD数据存储到磁盘和内存中。
模型上:
1.MapReduce可以处理超大规模的数据,适合日志分析挖掘等较少的迭代的长任务需求,结合了数据的分布式的计算。
- Spark:适合数据的挖掘,机器学习等多轮迭代式计算任务。
总结:
1)基于内存计算,减少低效的磁盘交互;
2)高效的调度算法,基于DAG;
3)容错机制Linage,精华部分就是DAG和Lingae
18.spark中的数据倾斜
1.什么是数据倾斜:
因为task是 并发执行的,所以有的task执行快,有的执行慢,或者等很长时间给你个提示说没内存了,导致的执行失败
2.原因:
数据问题
-
1、key本身分布不均衡(包括大量的key为空)
-
2、key的设置不合理
spark使用的问题
-
1、shuffle时的并发度不够
-
2、计算方式有误
3.造成的后果
-
1、spark中的stage的执行时间受限于最后那个执行完成的task,因此运行缓慢的任务会拖垮整个程序的运行速度(分布式程序运行的速度是由最慢的那个task决定的)。
-
2、过多的数据在同一个task中运行,将会把executor撑爆。
4.如何避免
发现数据倾斜的时候,不要急于提高executor的资源,修改参数或是修改程序,首先要检查数据本身,是否存在异常数据。找出异常的key
数据问题
如果任务长时间卡在最后最后1个(几个)任务,首先要对key进行抽样分析,判断是哪些key造成的。 选取key,对数据进行抽样,统计出现的次数,根据出现次数大小排序取出前几个。经过分析,倾斜的数据主要有以下三种情况:
- 1、null(空值)或是一些无意义的信息()之类的,大多是这个原因引起。
- 2、无效数据,大量重复的测试数据或是对结果影响不大的有效数据。
- 3、有效数据,业务导致的正常数据分布。
- 第1,2种情况,直接对数据进行过滤即可(因为该数据对当前业务不会产生影响)。
- 第3种情况则需要进行一些特殊操作,常见的有以下几种做法
- (1) 隔离执行,将异常的key过滤出来单独处理,最后与正常数据的处理结果进行union操作。
- (2) 对key先添加随机值,进行操作后,去掉随机值,再进行一次操作。
- (3) 使用reduceByKey 代替 groupByKey(reduceByKey用于对每个key对应的多个value进行merge操作,最重要的是它能够在本地先进行merge操作,并且merge操作可以通过函数自定义.)
- (4) 使用map join。
Spark操作问题
-
- 提高shuffle并行度
-
-
- dataFrame和sparkSql可以设置spark.sql.shuffle.partitions参数控制shuffle的并发度,默认为200。
-
- rdd操作可以设置spark.default.parallelism控制并发度,默认参数由不同的Cluster Manager控制。
- 局限性: 只是让每个task执行更少的不同的key。无法解决个别key特别大的情况造成的倾斜,如果某些key的大小非常大,即使一个task单独执行它,也会受到数据倾斜的困扰。
- 使用map join 代替reduce join
19.Spark streamning特点
Spark Streaming 是基于 RDD 的,因此需要将一小段时间内的,比如1秒内的数据,收集起来,作为一个 RDD,然后再针对这个 batch 的数据进行处理。Spark Streaming 是无法动态调整并行度 。流式处理完的数据,可以立即进行各种map、reduce转换操作,可以立即使用sql进行查询,甚至可以立即使用machine learning或者图计算算法进行处理。
注意:
-
只要一个StreamingContext启动之后,就不能再往其中添加任何计算逻辑了。
-
一个StreamingContext停止之后,是肯定不能重启的。调用
stop()
之后,不能再调用start()
-
一个JVM同时 只能有一个StreamingContext启动(和SparkContext一样)。在应用程序中,不能创建两个StreamingContext。
-
调用
stop()
方法时,会同时停止内部的SparkContext,如果希望后面继续使用SparkContext创建其他类型的Context,比如SQLContext,可以用stop(false)
。 -
一个SparkContext可以创建多个StreamingContext,只要上一个先用
stop(false)
停止,再创建下一个即可。
20.Spark中的血统
RDD是弹性分布式数据集,是Spark中最基本的数据抽象,代表一个不可变、可分区、里面的元素可并行计算 的集合。
它提供了一个抽象的数据模型,将具体的应用逻辑表达为一系列转换操作(函数)。另外不同RDD之间的转换操作之间还可以形成依赖关系,进而实现管道化,从而避免了中间结果的存储,大大降低了数据复制、磁盘IO和序列化开销,并且还提供了更多的API(map/reduec/filter/groupBy…)
RDD 的 lineage 记录的是粗颗粒度 的特定数据转换(transformation)操作(filter, map, join etc.)行为。当这个 RDD 的部分分区数据丢失时,它可以通过 lineage 获取足够的信息来重新运算和恢复丢失的数据分区。这种粗颗粒的数据模型,限制了 Spark 的运用场合,但同时相比细颗粒度的数据模型,也带来了性能的提升。
21.RDD共享变量
在应用开发中,一个函数被传递给Spark操作(例如map和reduce),在一个远程集群上运行,它实际上操作的是这个函数用到的所有变量的独立拷贝。这些变量会被拷贝到每一台机器。通常看来,在任务之间中,读写共享变量显然不够高效。然而,Spark还是为两种常见的使用模式,提供了两种有限的共享变量:广播变量和累加器
21.1广播变量(Broadcast Variables)
-
广播变量缓存到各个节点的内存中,而不是每个 Task
-
广播变量被创建后,能在集群中运行的任何函数调用
-
广播变量是只读的,不能在被广播后修改
-
对于大数据集的广播, Spark 尝试使用高效的广播算法来降低通信成本
-
val broadcastVar = sc.broadcast(Array(1, 2, 3))方法参数中是要广播的变量
21.2 累加器
累加器只支持加法操作,可以高效地并行,用于实现计数器和变量求和。Spark 原生支持数值类型和标准可变集合的计数器,但用户可以添加新的类型。只有驱动程序才能获取累加器的值
22.Spark 调优
参数调优
-
num-executors:设置Spark作业总共要用多少个Executor进程来执行
-
executor-memory:设置每个Executor进程的内存
-
executor-cores:设置每个Executor进程的CPU core数量
-
driver-memory:设置Driver进程的内存
-
spark.default.parallelism:设置每个stage的默认task数量
开发调优
-
避免创建重复的RDD
-
尽可能复用同一个RDD
-
对多次使用的RDD进行持久化
-
尽量避免使用shuffle类算子
-
使用map-side预聚合的shuffle操作
-
使用高性能的算子
23.Spark实现TopN
- 方法1:
(1)按照key对数据进行聚合(groupByKey)
(2)将value转换为数组,利用scala的sortBy或者sortWith进行排序(mapValues)
注意:当数据量太大时,会导致OOM
- 方法2:
(1)取出所有的key
(2)对key进行迭代,每次取出一个key利用spark的排序算子进行排序
- 方法3:
(1)自定义分区器,按照key进行分区,使不同的key进到不同的分区
(2)对每个分区运用spark的排序算子进行排序
24.RDD有几种操作类型
-
transformation,rdd由一种转为另一种rdd
-
action
-
cronroller,crontroller是控制算子,cache,persist,对性能和效率的有很好的支持三种类型
25.RDD的checkpoint
RDD的缓存能够在第一次计算完成后,将计算结果保存到内存、本地文件系统中。通过缓存,Spark避免了RDD上的重复计算,能够极大地提升计算速度。但是,如果缓存丢失了,则需要重新计算。如果计算特别复杂或者计算耗时特别多,那么缓存丢失对于整个Job的效率有很大影响,为了避免缓存丢失重新计算带来的开销,Spark又引入了检查点(checkpoint)机制。
缓存是在计算结束后,直接将计算结果通过用户定义的存储级别(存储级别定义了缓存存储的介质,现在支持内存、本地文件系统和Tachyon)写入不同的介质。而检查点不同,它是在计算完成后,重新建立一个Job来计算。为了避免重复计算,推荐 先将RDD缓存,这样就能保证检查点的操作可以快速完成。
26.RDD的弹性表现在哪 ?
-
自动的进行内存和磁盘的存储切换;
-
基于Lingage的高效容错;
-
task如果失败会自动进行特定次数的重试;
-
stage如果失败会自动进行特定次数的重试,而且只会计算失败的分片;
-
checkpoint和persist,数据计算之后持久化缓存
-
数据调度弹性,DAG TASK调度和资源无关
-
数据分片的高度弹性,a.分片很多碎片可以合并成大的,b.par