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来实现的。receiverKafka中获取的数据都是存储在Spark Executor的内存中的,然后Spark Streaming启动的job回去处理那些数据。

2)基于Direct的方式

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

 

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

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

Cache不是action操作。

 

五、ReduceByKey是action算子嘛?

ReduceByKey是transform算子,reduce是action算子

 

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

Dag在划分stage时确定。

 

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

  1. 自动的进行内存和磁盘的存储切换
  2. 基于Lineage的高效容错
  3. Task如果失败会自动进行特定次数的重试
  4. Stage如果失败会自动进行特定次数的重试,而且只会计算失败的分片
  5. Cache和persist,数据计算之后持久化缓存
  6. 数据调度弹性,DAG TASK调度和资源无关
  7. 数据分片的高度弹性,a.分片很多碎片可以合并成大的

 

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

  1. 数据检查点(checkpoint),会发生拷贝,浪费资源
  2. 记录数据的更新,每次更新都会记录下来,复杂且消耗性能

详见:Spark容错机制

 

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

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

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

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

 

十、RDD有哪些缺陷?

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

 

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

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

 

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

  1. 前提是定位数据倾斜,是OOM还是任务执行缓慢,查看日志或者看4040weburl
  2. 解决方法:

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

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

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

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

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

 

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

  1. 使用程序中的集合创建rdd(.parallelize)
  2. 使用本地文件系统创建rdd(.textfile)
  3. 使用hdfs创建rdd
  4. 基于数据库db创建rdd
  5. 基于nosql创建rdd,如hbase
  6. 基于s3创建rdd
  7. 基于数据流创建rdd,如socket

 

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

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

 

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

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

 

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

Spark的数据本地性有三种:

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

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

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

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

 

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

  1. transformation,rdd由一种转为另一种rdd
  2. Action,reduce,collect...
  3. Crontrollercrontroller是控制算子,cache,persist,对性能和效率的有很好的支持。

 

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

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

 

 

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

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

 

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

  1. 输入数据有很多task,尤其是有很多小文件的时候,有多少个输入block就有多少个task
  2. Spark中有partition的概念。每个partition对应一个task,task越多,在处理大规模数据的时候,就会越有效率。不过task并不是越多越好,如果数据量不大,则没必要启动太多task;
  3. 参数可以通过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:

  1. 某个步骤计算非常耗时,需要进行persist持久化
  2. 计算链条非常长,重新恢复要算很多步骤
  3. Checkpoint所在的rdd要持久化persist,lazy级别,框架发现有checkpoint时单独触发一个job,需要重新算一遍,checkpoint前要持久化,写个rdd.cache或者rdd.persist,将结果保存起来,再写checkpoint操作,这样执行起来会非常快,不需要重新计算rdd链条了。
  4. Shuffle之后要persist,shuffle要进行网络传输,风险很大,数据丢失重来,恢复代价很大
  5. 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 的过程,运行时间得到大量缩短,根据不同数据可能会有几倍到数十倍的性能提升。

你可能感兴趣的:(面试题,spark,大数据)