目录
一. Spark有几种部署方式?请分别简要论述
二. Spark提交作业参数
三. 如何理解Spark中RDD的血缘关系?
四. 简述Spark的宽窄依赖,以及Spark如何划分stage,每个stage又根据什么决定task个数?
五. 请列举Spark的transformation算子,并简述功能
七. 请描述Repartition和Coalesce联系与区别
八. 分别简述Spark中的缓存机制与checkpoint机制,并指出两者的区别与联系。
九. 简述Spark中共享变量(广播变量和累加器)的基本原理与用途。
十. 当Spark涉及到外部数据库的操作时,如何减少Spark运行中的数据库连接数?
十一. SparkSQL中join操作与left join操作的区别?
十二. 请手写出wordcount的Spark代码实现(Scala)
十三. 如何使用Spark实现topN的获取(描述思路或使用伪代码)
往期精选
转载是一种动力 分享是一种美德, 欢迎关注 大数据与数据仓库公众号
spark主要有如下四种部署方式,分别如下:
1. Local
Spark运行在一台机器上,通常用于代码测试或者学习。
2. Standalone
构建一个基于Master与Slaves的资源调度集群,Spark任务提交给Master运行。
3. Yarn
Spark客户端直连Yarn,不需要额外构建Spark集群。包含yarn-client和yarn-cluster两种模式,主要区别在于Driver程序的运行节点。
4. Mesos
国内公司用的比较少。
在提交任务时的几个重要参数如下:
参数 | 注释 |
---|---|
executor-cores | 每个executor使用的内核数(默认为1) 官方建议2-5个 |
num-executors | 启动executors的数量(默认为2) |
executor-memory | executor内存大小(默认1G) |
driver-cores | driver使用内核数(默认为1) |
driver-memory | driver内存大小(默认512M) |
如下所示为个提交任务的样例
spark-submit \
--master local[8] \
--driver-cores 2 \
--driver-memory 16g \
--executor-cores 4 \
--num-executors 10 \
--executor-memory 8g \
--class PackageName.ClassName XXXX.jar \
--name "Spark Job Name" \
InputPath \
OutputPath
RDD在血缘依赖方面分为两种,分别是窄依赖(Narrow Dependencies)与宽依赖(Wide Dependencies),它在数据容错以及划分任务时候起到重要作用。
Stage划分: 根据RDD之间的依赖关系的不同将Job划分成不同的Stage,当遇到宽依赖时划分新的Stage。
Task个数:每个Stage是一个TaskSet,Stage根据分区数被划分成多个Task。
返回一个新的RDD,上游RDD中的每一个输入元素经过func函数转换后返回新的RDD.
2. mapPartitions(func)
与map类似,但其在RDD的每一个分区上独立运行。对于有m个元素,n个分区的RDD,mapPartitions被调用n次(调用次数与分区个数一致)。
3. reduceByKey(func,[numTask])
在一个(K,V) 的RDD上调用,返回一个(K,V)的RDD,reduce函数可以将具有相同key值的元素聚合到一起,reduce任务的并行度可以通过第二个可选的参数来配置。
4. aggregateByKey (zeroValue:U,[partitioner: Partitioner]) (seqOp: (U, V) => U,combOp: (U, U) => U
在kv对的RDD中,按key将value进行分组合并,合并时将每个value和初始值作为seq函数的参数进行计算,返回的结果作为一个新的kv对,然后再将结果按照key进行合并,最后将每个分组的value传递给combine函数进行计算(先将前两个value进行计算,将返回结果和下一个value传给combine函数,以此类推),将key与计算结果作为一个新的kv对输出。
六. Spark常用算子reduceByKey与groupByKey的区别,哪一种更具优势?
按照key进行聚合,在shuffle之前有预聚合(combine)操作,返回结果为RDD[k,v]。
2. groupByKey
按照key进行分组后直接shuffle(无预聚合)。
预聚合可以提高执行性能,在不影响业务逻辑的情况下,建议优先使用reduceByKey。
两者都可以用于改变RDD的partition数量,repartition底层调用的就是coalesce方法:coalesce(numPartitions, shuffle = true)
repartition一定会发生shuffle,coalesce根据传入的参数来判断是否发生shuffle。
一般情况下增大RDD的分区数量使用repartition算子,减少分区数量时使用coalesce算子。
Spark中的缓存机制包括cache与persist,与checkpoint机制一样都是用于RDD持久化。
其中缓存机制不会截断血缘关系。
checkpoint 会截断血缘关系,在checkpoint之前必须没有任何任务提交才会生效,checkpoint过程会额外提交一次任务。
累加器(accumulator)是Spark中提供的一种分布式的变量机制,其原理类似于mapreduce,即分布式的改变,然后聚合这些改变。累加器的一个常见用途是在调试时对作业执行过程中的事件进行计数。而广播变量用来高效分发较大的对象。
共享变量出现的原因:
通常在向 Spark 传递函数时,比如使用 map() 函数或者用 filter() 传条件时,可以使用驱动器程序中定义的变量,但是集群中运行的每个任务都会得到这些变量的一份新的副本,更新这些副本的值也不会影响驱动器中的对应变量。
Spark的两个共享变量,累加器与广播变量分别为结果聚合与广播这两种常见的通信模式突破了这一限制。
使用foreachPartition代替foreach,在foreachPartition内获取数据库的连接。
SparkSQL中的join算子用于返回的是前面一个集合和后面一个集合可以成功匹配的数据(无法匹配的数据被过滤)。
left join返回结果以第一个RDD为主,第二个RDD中关联不上的记录置为空。
多插一句,部分场景下可以使用left semi join替代left join。
由于 left semi join 是 in (keySet) 的关系,遇到右表重复记录,左表会跳过,性能更高,而 left join 则会一直遍历。需要注意的是left semi join 中最后 select 的结果中只会出现左表中的列。
val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("WordCount")
val sc = new SparkContext(conf)
sc.textFile("/input")
.flatMap(_.split(" "))
.map((_,1))
.reduceByKey(_+_)
.saveAsTextFile("/output")
sc.stop()
方法1:
(1)按照key对数据进行聚合(groupByKey)
(2)将value转换为数组,利用scala的sortBy或者sortWith进行排序(mapValues),需要注意如果数据量太大,会发生OOM。
方法2:
(1)取出所有的key
(2)对key进行迭代,每次取出一个key利用spark的排序算子进行排序
方法3:
(1)自定义分区器,按照key进行分区,使不同的key进到不同的分区
(2)对每个分区运用spark的排序算子进行排序
Spark性能调优之在实际项目中广播大变量
Spark Shuffle调优之调节map端内存缓冲与reduce端内存占比
Spark Shuffle调优之合并map端输出文件
Flink调优法则
5个Hadoop优化技巧
4个角度轻松理解 Flink中的Watermark
Flink中Checkpoint和Savepoint 的 3 个不同点
Flink实现固定时长或消息条数的触发器
Flink方案设计中的4大误区
使用 Broadcast State 的 4 个注意事项
3种Flink State Backend | 你该用哪个?
一文搞定 Flink 异步 I/O
Flink State 使用的4点建议
Flink在开发中的7点建议