Spark面试题(一)

一、spark集群运算的模式

Spark 有很多种模式,最简单就是单机本地模式,还有单机伪分布式模式,复杂的则运行在集群中,目前能很好的运行在 Yarn和 Mesos 中,当然 Spark 还有自带的 Standalone 模式,对于大多数情况 Standalone 模式就足够了,如果企业已经有 Yarn 或者 Mesos 环境,也是很方便部署的。

standalone(集群模式):典型的Mater/slave模式,不过也能看出Master是有单点故障的;Spark支持ZooKeeper来实现 HA

on yarn(集群模式): 运行在 yarn 资源管理器框架之上,由 yarn 负责资源管理,Spark 负责任务调度和计算

on mesos(集群模式): 运行在 mesos 资源管理器框架之上,由 mesos 负责资源管理,Spark负责任务调度和计算。

on cloud(集群模式):比如 AWS 的 EC2,使用这个模式能很方便的访问 Amazon的 S3;Spark支持多种分布式存储系统:HDFS和S3

二、RDD中reduceBykey与groupByKey哪个性能好,为什么?

reduceByKey:reduceByKey会在结果发送至reducer之前会对每个mapper在本地进行merge,有点类似于在MapReduce中的combiner。这样做的好处在于,在map端进行一次reduce之后,数据量会大幅度减小,从而减小传输,保证reduce端能够更快的进行结果计算。

groupByKey:groupByKey会对每一个RDD中的value值进行聚合形成一个序列(Iterator),此操作发生在reduce端,所以势必会将所有的数据通过网络进行传输,造成不必要的浪费。同时如果数据量十分大,可能还会造成OutOfMemoryError。

通过以上对比可以发现在进行大量数据的reduce操作时候建议使用reduceByKey。不仅可以提高速度,还是可以防止使用groupByKey造成的内存溢出问题。

三、如何从kafka中获取数据?

1)基于Receiver的方式

这种方式使用Receiver来获取数据。Receiver是使用Kafka的高层次Consumer API来实现的。receiver从Kafka中获取的数据都是存储在Spark Executor的内存中的,然后Spark Streaming启动的job回去处理那些数据。

2)基于Direct的方式

这种新的不基于Receiver的直接方式,是在Spark 1.3中引入的,从而能够确保更加健壮的机制。替代掉使用Receiver来接收数据后,这种方式会周期性地查询Kafka,来获得每个topic+partition的最新的offset,从而定义每个batch的offset的范围。当处理数据的job启动时,就会使用Kafka的简单consumer api来获取Kafka指定offset范围的数据

四、cache后面能不能接其他算子,它是不是action操作?

Cache后可以接其他算子,但是接了算子之后,起不到缓存的作用,因为会重复出发cache。

Cache不是action操作。

五、ReduceByKey是action算子嘛?

ReduceByKey是transform算子,reduce是action算子

六、数据本地性是在哪个阶段确定的?

Dag在划分stage时确定。

七、RDD的弹性体现在什么方面?

自动的进行内存和磁盘的存储切换

基于Lineage的高效容错

Task如果失败会自动进行特定次数的重试

Stage如果失败会自动进行特定次数的重试,而且只会计算失败的分片

Cache和persist,数据计算之后持久化缓存

数据调度弹性,DAG TASK调度和资源无关

数据分片的高度弹性,a.分片很多碎片可以合并成大的

八、常规的容错方式有哪几种?

数据检查点(checkpoint),会发生拷贝,浪费资源

记录数据的更新,每次更新都会记录下来,复杂且消耗性能

详见:Spark容错机制

九、RDD通过Lineage(记录数据更新)方式为何很高效?

1)lazy记录了数据的来源,RDD是不可变的,且是lazy级别的,且rDD之间构成了链条,lazy是弹性的基石。由于RDD不可变,所以每次操作就产生新的rdd,不存在全局修改的问题,控制难度下降,所有有计算链条将复杂计算链条存储下来,计算的时候从后往前回溯900步是上一个stage的结束,要么就checkpoint

2)记录原数据,是每次修改都记录,代价很大如果修改一个集合,代价就很小,官方说rdd是粗粒度的操作,是为了效率,为了简化,每次都是操作数据集合,写或者修改操作,都是基于集合的rdd的写操作是粗粒度的,rdd的读操作既可以是粗粒度的也可以是细粒度,读可以读其中的一条条的记录。

3)简化复杂度,是高效率的一方面,写的粗粒度限制了使用场景如网络爬虫,现实世界中,大多数写是粗粒度的场景

十、RDD有哪些缺陷?

不支持细粒度的写和更新操作,spark写数据是粗粒度的。所谓粗粒度,就是批量写入数据,为了提高效率。但是读数据是细粒度的,也就是说是一条一条读的。

不支持增量迭代计算,Flink支持。

十一、Spark有哪些聚合类的算子,我们应该避免什么类型的算子?

在我们的开发过程中,能避免则尽量避免使用reduceByKey、groupByKey、join、dictinct,repartition等会进行shuffle的算子,尽量使用map类的非shuffle算子。这样的话,没有shuffle操作或者仅有较少的shuffle操作的Spark作业,可以大大减少性能开销。

十二、对于spark中的数据倾斜问题有什么好的方案?

前提是定位数据倾斜,是OOM还是任务执行缓慢,查看日志或者看4040weburl

解决方法:

· 避免不必要的shuffle,如使用广播小表的方式,将reduce-side-join提升为map-side-join

· 分拆发生数据倾斜的记录,分成几个部分进行,然后合并join后的结果

· 改变并行度,可能并行度太少了,导致个别task数据压力大

· 两阶段聚合,先局部聚合,再全局聚合

· 自定义partitioner,分散key的分布,使其更加均匀

十三、RDD创建有哪几种方式?

使用程序中的集合创建rdd(.parallelize)

使用本地文件系统创建rdd(.textfile)

使用hdfs创建rdd

基于数据库db创建rdd

基于nosql创建rdd,如hbase

基于s3创建rdd

基于数据流创建rdd,如socket

十四、Spark中并行度怎么设置比较合适?

Spark并行度,每个core承载24个partition,32core,那么64128之间的并行度,也就是设置64~128个partition,并行度和数据规模无关,只和内存使用量和cpu使用时间有关。

十五、Spark中的数据的位置是由谁来管理的?

每个数据分片都对应具体物理位置,数据位置是由blockManager管理,无论数据是在磁盘,内存还是tacyan,都由blockManager管理。

十六、spark的数据本地性有哪几种?

Spark的数据本地性有三种:

PROCESS_LOCAL是指读取缓存在本地节点的数据

NODE_LOCAL是指读取本地节点磁盘的数据

ANY是指读取非本地节点的数据

通常读取数据PROCESS_LOCAL>NODE_LOCAL>ANY,尽量使数据以PROCESS_LOCAL或NODE_LOCAL方式读取。其中PROCESS_LOCAL还和cache有关,如果RDD经常用的话将该RDD cache到内存中,注意,由于cache是lazy的,所以必须通过一个action的触发,才能真正的将该RDD cache到内存中。

十七、RDD有几种操作算子类型?

transformation,rdd由一种转为另一种rdd

Action,reduce,collect...

Crontroller,crontroller是控制算子,cache,persist,对性能和效率的有很好的支持。

十八、Spark如何处理不能被序列化的对象?

将不能序列化的内容封装成object

十九、collect的功能是什么?其底层如何实现的?

Driver将集群中各节点的内容收集起来汇总成结果,collect返回的类型为Array,collect把各个节点上的数据抓过来,抓过来数据是Array类型,collect对Array抓过来的结果进行合并,合并后Array中只有一个元素,是tuple类型(KV)的。

二十、Spark程序执行,有时候默认为什么会产生很多task,怎么修改默认task执行个数?

输入数据有很多task,尤其是有很多小文件的时候,有多少个输入block就有多少个task

Spark中有partition的概念。每个partition对应一个task,task越多,在处理大规模数据的时候,就会越有效率。不过task并不是越多越好,如果数据量不大,则没必要启动太多task;

参数可以通过spark_home/conf/spark-default.conf配置文件设置:

spark.sql.shuffle.partitions 50 spark.default.parallelism 10

第一个是针对spark sql的task数量

第二个是非spark sql程序设置生效

二十一、为什么Spark Application在没有获得足够的资源,job就开始执行了,可能会导致什么问题发生?

会导致执行该job时候集群资源不足,导致执行job结束也没有分配足够的资源,分配了部分Executor,该job就开始执行task,应该是task的调度线程和Executor资源申请是异步的。

二十二、map和flatmap的区别?

Map:对RDD每个元素转换,文件中每一行的数据返回一个数组对象。

Flatmap:对RDD每个元素转换,然后再扁平化将所有对象合并成一个对象,文件中的所有行数据金返回一个数组对象,会抛弃为null的值。

二十三、Spark为什么要持久化,一般什么场景下要进行persist操作?

Spark所有复杂的算法都会有persist的身影,spark默认数据放在内存,spark很多内容都是放在内存的,非常适合高速迭代,1000个步骤,只有第一个输入数据,中间不产生临时数据,但分布式系统风险很高,所以容易出错,就要容错,rdd出错或者分片可以根据血统算出来,如果没有对父rdd进行persist或者cache的话,就需要重头做。

以下场景要进行persist:

某个步骤计算非常耗时,需要进行persist持久化

计算链条非常长,重新恢复要算很多步骤

Checkpoint所在的rdd要持久化persist,lazy级别,框架发现有checkpoint时单独触发一个job,需要重新算一遍,checkpoint前要持久化,写个rdd.cache或者rdd.persist,将结果保存起来,再写checkpoint操作,这样执行起来会非常快,不需要重新计算rdd链条了。

Shuffle之后要persist,shuffle要进行网络传输,风险很大,数据丢失重来,恢复代价很大

Shuffle之前要persist,框架默认将数据持久化到磁盘,这个是框架自动做的

二十四、为什么要进行序列化

序列化可以减少数据的体积,减少存储空间,高效存储和传输数据,不好的是使用的时候要反序列化,非常消耗cpu。

二十五、介绍一下join操作优化经验?

join其实常见的就分为两类: map-side join 和  reduce-side join。当大表和小表join时,用map-side join能显著提高效率。将多份数据进行关联是数据处理过程中非常普遍的用法,不过在分布式计算系统中,这个问题往往会变的非常麻烦,因为框架提供的 join 操作一般会将所有数据根据 key 发送到所有的 reduce 分区中去,也就是 shuffle 的过程。造成大量的网络以及磁盘IO消耗,运行效率极其低下,这个过程一般被称为 reduce-side-join。如果其中有张表较小的话,我们则可以自己实现在 map 端实现数据关联,跳过大量数据进行 shuffle 的过程,运行时间得到大量缩短,根据不同数据可能会有几倍到数十倍的性能提升。

posted @ 2019-02-24 21:51  sandywei  阅读(1612)  评论(0编辑  收藏  举报