Hive 面试总结传送门:大数据岗位校招Hive面试总结

Hadoop 面试总结传送门: 大数据岗位校招Hadoop面试总结

继上一篇Hive相关的面试总结后,本篇总结下Spark相关的问题~

  • 1、Spark基本概念
  • 2、Spark运行流程
  • 3、Spark on yarn—cilent 和 on yarn—cluster 的区别
  • 4、Spark 怎样划分stage和task
  • 5、stage的调度与task的调度
  • 6、静态资源申请与动态资源申请
  • 7、Spark内存管理机制
  • 8、Spark standalone模型
  • 9、Spark开发调优
  • 10、Spark数据倾斜及调优
  • 11、Spark里面有哪些参数可以设置,有什么用
  • 12、Spark shuffle参数调优
  • 13、Spark 持久化级别
  • 14、Spark RDD、DataFrame、DataSet区别,为什么DataFrame和DataSet比RDD快
  • 15、RDD弹性体现在哪些方面
  • 16、Spark有哪几种join、join的实现
  • 17、Spark join算子可以用什么替代
  • 18、Spark shuffle原理
  • 19、Spark shuffle类算子
  • 20、block和partition的关系
  • 21、reduceByKey和groupByKey的区别
  • 22、repartition和coalease的区别
  • 23、为什么划分宽窄依赖
  • 24、SparkSession和SparkContext
  • 25、Spark广播变量和累加器
  • 26、hashpartitioner与rangePartitioner的实现
  • 27、Spark为什么比Hadoop快
  • 28、Spark常见算子的作用

1、Spark基本概念

  1. Driver:main()函数,创建SparkContext,由SparkContext进行资源申请,任务的分配和监控等。程序执行完毕后关闭SparkContext。
  2. Executor:某个应用运行在worker节点上的一个进程,该进程负责运行某些task,将Task包装成taskRunner,并从线程池中抽取出一个空闲线程运行Task,并将数据存在内存或者磁盘上。
  3. Worker:集群中可以运行Application代码的节点,在Standalone模式中指的是通过slave文件配置的worker节点,在Spark on Yarn模式中指的就是NodeManager节点。
  4. job:包含多个task的并行计算,由action触发
  5. stage:每个job被划分为多个stage,一个stage中包含一个taskset
  6. task:在executor进程中执行任务的工作单元

2、Spark运行流程

Spark运行流程比较复杂,在此仅简单描述必要流程

  1. Client向YARN的 RM 申请启动 AM 。同时在client中运行的 driver 会初始化 SparkContext ,Driver进程本身会根据我们设置的参数,占有一定数量的内存和CPU core。SC初始化中将创建DAGScheduler和TASKScheduler、HeartbeatReceiver。
  2. RM 收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,与YARN-Cluster区别的是在该 AM 不运行SparkContext,只与SparkContext进行联系进行资源的分派;
  3. Client中的SparkContext初始化完毕后,与ApplicationMaster建立通讯,向ResourceManager注册,根据任务信息向ResourceManager申请资源(executor中的Container)
  4. 一旦 AM 申请到资源(也就是Container,container中运行的是executor进程)后,便与对应的NodeManager通信,要求它在获得的Container中启动一些Backend进程,启动后会向SparkContext注册并申请Task
  5. Driver进程将Spark作业代码分拆为多个stage,每个stage执行一部分代码片段,并为每个stage创建一批task,Client中的SparkContext分配Task给executor执行,executor向Driver汇报运行的状态和进度,以让Client随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务;(task是最小的计算单元,负责执行一模一样的计算逻辑(也就是我们自己编写的某个代码片段),只是每个task处理的数据不同而已。)一个stage的所有task都执行完毕之后,会在各个节点本地的磁盘文件中写入计算中间结果,然后Driver就会调度运行下一个stage。下一个stage的task的输入数据就是上一个stage输出的中间结果。循环往复,直到执行完。
  6. 应用程序运行完成后,Client的SparkContext向ResourceManager申请注销并关闭自己。

3、Spark on yarn—cilent 和 on yarn—cluster 的区别

  1. cluster:driver运行在AM中,它负责向YARN申请资源,并监督作业的运行状况。用户提交了作业之后,就可以关掉Client,作业会继续在YARN上运行,因而Cluster模式不适合运行交互类型作业
  2. client:AM 仅仅向YARN请求Executor,Client会和请求的Container通信来调度他们工作,也就是说Client不能离开。

4、Spark 怎样划分stage和task

stage划分

在spark中,会根据RDD之间的依赖关系划分DAG图,对于窄依赖,由于partition依赖关系的确定性,可以在同一个线程里完成,窄依赖就被spark划分到同一个stage中,而对于宽依赖,只能等父RDD shuffle处理完成后,下一个stage才能开始接下来的计算。

stage划分思路

从后往前推,遇到宽依赖就断开,划分为一个stage,遇到窄依赖就将这个RDD加入该stage中。

task划分

  1. ResultTask获取父RDD分区数据之后,把分区数据作为参数输入到action函数中,最终计算出特定的结果返回给driver。
  2. ShuffleMapTask获取父RDD分区数据之后,把分区数据作为参数传入分区函数,最终形成新的RDD中的分区数据,保存在各个Executor节点中

5、stage的调度与task的调度

stage调度

通过Action的调用,触发Job并调度执行。DAGScheduler负责Stage级的调度,将DAG切分成若干Stages,并将每个Stage打包(task的分区信息和方法,并序列化)成TaskSet交给TaskScheduler调度。

划分的Stages分两类,一类叫做ResultStage,为DAG最下游的Stage,由Action方法决定,另一类叫做ShuffleMapStage,为下游Stage准备数据。

TaskScheduler负责Task级的调度,将DAGScheduler给过来的TaskSet按照指定的调度策略分发到Executor上执行,调度过程中SchedulerBackend负责提供可用资源(SchedulerBackend有多种实现对应多种资源管理系统)

task调度

TaskScheduler 会将发来的 taskSet 封装为TaskSetManager加入到调度队列中,TaskSetManager负责监控管理同一个Stage中的Tasks,TaskScheduler就是以TaskSetManager为单元来调度任务。

TaskScheduler 初始化后会启动SchedulerBackend(接收Executor的注册信息,并维护Executor的状态),SchedulerBackend 会定期询问 TaskScheduler 有没有任务要运行,TaskScheduler会从调度队列中按照指定的调度策略选择 TaskSetManager 去调度运行。

TaskScheduler支持两种调度策略,一种是FIFO(默认),另一种是FAIR。

从调度队列中拿到 TaskSetManager 后,接下来的工作就是 TaskSetManager 按照一定的规则一个个取出 Task 给 TaskScheduler,TaskScheduler 再交给 SchedulerBackend 去发到 Executor 上执行。

6、静态资源申请与动态资源申请

  1. 静态资源申请:用户在提交Spark应用程序时,就要提前估计应用程序需要使用的资源(使用参数设定),任务的并行度由分区数决定,一个Stage有多少分区,就会有多少Task。每个Task默认占用一个Core,一个Executor上的所有core共享Executor上的内存,一次并行运行的Task数等于num_executor*executor_cores
  2. 动态资源申请:目前只支持到Executor,即可以不用指定num_executor,通过参数spark.dynamicAllocation.enabled 来控制。由于许多Spark应用程序一开始可能不需要那么多Executor或者其本身就不需要太多Executor,所以不必一次性申请那么多Executor,根据具体的任务数动态调整Executor的数量,尽可能做到资源的不浪费。动态Executor的调整会导致Executor动态的添加与删除,如果删除Executor,上面的中间Shuffle结果可能会丢失

7、Spark内存管理机制

静态内存管理

堆内:存储内存、执行内存、其他内存的大小在 Spark 应用程序运行期间均为固定的,但用户可在应用程序启动前配置,默认storage 60%(60%中预留了6%防止OOM,但只是逻辑上的,实际中spark没有区别对待,和其他内存一样全部交给JVM管理),execution 20%,other 20%。

堆外:只有存储内存、执行内存,由于堆外内存占用的空间可以被精确计算,所以无需再设定保险区域。默认情况下各占50%

缺点:需要根据具体的数据规模和计算任务调整,很容易不平衡(一个闲着,一个严重不足)

统一内存管理

存储内存和执行内存共享同一块空间,可以动态占用对方的空闲区域。

动态占用机制:

  1. 设定基本的storage和execution区域,默认为各30%,other占40%。(堆内)
  2. 双方空间都不足时(指不足以放下一个完整的block),写磁盘,自己不足对方剩余时,可以借用对方空间。
  3. execution的空间被storage占用后,可以让storage将占用的部分存到磁盘,归还空间。
  4. storage的空间被execution占用后,无法强制对方归还。
  5. 堆外也是动态占用机制,storage和execution各50%。

8、Spark standalone模型

运行过程较为复杂,在此仅简单描述运行过程:

  1. 提交一个Application,初始化SparkContext,初始化DAG Scheduler和Task Scheduler
  2. Task Scheduler向Master去进行注册并申请资源(CPU Core和Memory)
  3. Master根据 SparkContext 的资源申请和 Worker 心跳信息决定在哪个Worker上分配资源,然后在该Worker上获取资源,启动StandaloneExecutorBackend;顺便初始化好了一个线程池
  4. StandaloneExecutorBackend向Driver(SparkContext)注册,这样Driver就知道哪些Executor为他进行服务了。初始化基本完成。
  5. SparkContext解析Applicaiton代码,构建DAG图,并提交给DAG Scheduler分解成Stage
  6. 将Stage(或者称为TaskSet)提交给Task Scheduler。Task Scheduler负责将Task分配到相应的Worker,最后提交给StandaloneExecutorBackend执行
  7. 对task进行序列化,并根据task的分配算法,分配task
  8. 对接收过来的task进行反序列化,把task封装成一个线程
  9. 开始执行Task,并向SparkContext报告,直至Task完成
  10. 资源注销

9、Spark开发调优

  1. 避免创建重复的RDD,对于同一份数据,只应该创建一个RDD。有重复意味着spark会进行多次计算创建代表相同数据的RDD,增加开销
  2. 尽可能重复使用同一个RDD,多个RDD的数据有重叠或者包含的情况,应该尽量复用一个RDD,这样可以尽可能地减少RDD的数量,从而尽可能减少算子执行的次数。
  3. 对多次使用的RDD持久化,保证对一个RDD执行多次算子时,这个RDD本身仅仅被计算一次。
  4. 避免使用shuffle类算子,shuffle会造成网络开销以及磁盘IO操作,限制性能,尽可能避免使用reduceByKey、join、distinct、repartition等
  5. 使用优化的算子。
  6. 广播大变量,需要在算子函数中使用外部变量的场景(大变量),应该broadcast,默认情况下,Spark会将该变量复制多个副本,通过网络传输到task中,此时每个task都有一个变量副本。大量的变量副本==>网络中传输的性能开销、各个节点的Executor中占用过多内存导致的频繁GC
  7. 使用kyro优化序列化性能(用到序列化的地方:1.算子中用到外部变量时,会先序列化再网络传输;2.自定义的类型作为RDD泛型类型时,实现Serailizable接口;3.使用序列化的持久化策略时),spark默认的是Java序列化,kyro效率更高,但需要注册所有需要序列化的自定义类
  8. 优化数据结构,尽量少用对象、字符串、集合类。尽量使用字符串替代对象,使用原始类型(比如Int、Long)替代字符串,使用数组替代集合类型,尽可能地减少内存占用,从而降低GC频率

10、Spark数据倾斜及调优

数据倾斜的现象

绝大多数task执行得都非常快,但个别task执行极慢

数据倾斜的原理

在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,此时如果某个key对应的数据量特别大的话,就会发生数据倾斜。比如大部分key对应10条数据,但是个别key却对应了100万条数据,那么大部分task可能就只会分配到10条数据,然后1秒钟就运行完了;但是个别task可能分配到了100万数据,要运行一两个小时。

如何定位数据倾斜

  1. 只会发生在shuffle过程中,可能会触发shuffle操作的算子:distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等
  2. 在web UI上查看,看日志,在代码第几行溢出,附近的shuffle算子
  3. 查看出现问题的RDD或hive表的key分布状况,用countByKey统计一下

数据倾斜解决方案

  1. 对Hive表数据进行预聚合和预处理,过滤导致倾斜的key
  2. 提高shuffle的并行度,让原本分配给一个task的多个key分配给多个task,从而让每个task处理比原来更少的数据。
  3. 两阶段聚合(局部聚合+全局聚合),局部聚合,给每个key都打上一个随机数,此时原先一样的key就变成不一样的了,比如(hello, 1) (hello, 1) (hello, 1) (hello, 1),就会变成(1_hello, 1) (1_hello, 1) (2_hello, 1) (2_hello, 1)。接着对打上随机数后的数据,执行reduceByKey等聚合操作,进行局部聚合,那么局部聚合结果,就会变成了(1_hello, 2) (2_hello, 2),然后将各个key的前缀给去掉,就会变成(hello,2)(hello,2),再次进行全局聚合操作,就可以得到最终结果了,比如(hello, 4)。
  4. 将reduce join替换为map join:将小的broadcast广播,在大的里面用map遍历,看key是否相同
  5. 使用随机前缀和扩容RDD进行join:将造成倾斜的RDD的每条数据都打上一个n以内的随机前缀;对另外一个正常的RDD进行扩容,将每条数据都扩容成n条数据,扩容出来的每条数据都依次打上一个0~n的前缀(确保无论第一个RDD被打上哪个随机前缀,都保证扩容后的RDD中某一条能和他join上);最后将两个处理后的RDD进行join即可

11、Spark里面有哪些参数可以设置,有什么用

  1. spark.app.name:应用程序的名称
  2. spark.driver.cores:在cluster模式下,用几个core运行驱动器(driver)进程。
  3. spark.driver.maxResultSize:Spark action算子返回的结果最大多大,每个Spark动作(例如collect)的所有分区的序列化结果的总大小限制,如果总数超过这个限制,工作将会被中止。具有高限制可能会导致驱动程序内存不足错误
  4. spark.driver.memory:用于驱动程序进程的内存量,1G一般足够,即SparkContext被初始化的地方,如果需要使用collect算子将RDD的数据全部拉取到Driver上进行处理,那么必须确保Driver的内存足够大,否则会出现OOM
  5. num-executors:设置Spark作业总共要用多少个Executor进程来执行。每个Spark作业的运行一般设置50~100个左右的Executor进程比较合适
  6. spark.executor.memory(OOM可能与此关联):每个执行程序进程使用的内存量,每个Executor进程的内存设置4G~8G较为合适。
  7. executor-cores:设置每个Executor进程的CPU core数量。决定了每个Executor进程并行执行task线程的能力。每个CPU core同一时间只能执行一个task线程。Executor的CPU core数量设置为2~4个较为合适。最好的应该就是一个cpu core对应两到三个task
  8. spark.default.parallelism:设置每个stage的默认task数量。这个参数其实就是设置task的数量,500-1000个比较合适,不设置的话,Spark自己根据底层HDFS的block数量来设置task的数量,默认是一个HDFS block对应一个task,偏少
  9. spark.storage.memoryFraction:该参数用于设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。Executor 60%的内存,可以用来保存持久化的RDD数据。
  10. spark.shuffle.memoryFraction:该参数用于设置shuffle过程中一个task拉取到上个stage的task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2。

12、Spark shuffle参数调优

  1. spark.shuffle.file.buffer(可以适当增加,减少IO):该参数用于设置shuffle write task的buffer缓冲大小。将数据写到磁盘文件之前,会先写入buffer缓冲中,待缓冲写满之后,才会溢写到磁盘。
  2. spark.reducer.maxSizeInFlight(可以适当增加):该参数用于设置shuffle read task的buffer缓冲大小,而这个buffer缓冲决定了每次能够拉取多少数据。
  3. spark.shuffle.io.maxRetries(增大):shuffle read task从shuffle write task所在节点拉取属于自己的数据时,如果因为网络异常导致拉取失败,最大重试次数。
  4. spark.shuffle.io.retryWait(增大):每次重试拉取数据的等待间隔

13、Spark 持久化级别

MEMORY_ONLY、
MEMORY_AND_DISK、
MEMORY_ONLY_SER、
MEMORY_AND_DISK_SER、
DISK_ONLY、
MEMORY_ONLY_2等 (2表示对持久化的数据,复制一个副本保存到其他节点)

14、Spark RDD、DataFrame、DataSet区别,为什么DataFrame和DataSet比RDD快

  1. RDD:弹性分布式数据集,spark中最基本的数据抽象,不可变,可分区,里面元素可并行计算,分片(RDD的属性,数据集的基本组成单位,每个分片会被一个计算任务处理,并决定并行计算的粒度),partitioner(分片函数,分为 hash、range partitioner ,只有 K-V 类型的RDD才有partitioner),DataFrame 和 Dataset 也正是基于 RDD 提供的,可以通过简单的 API 方法调用在 DataFrame 或 Dataset 与 RDD 之间进行无缝切换
  2. DataFrame:Spark-SQL最核心的编程抽象,可以从结构化数据文件,hive中的表,外部关系型数据库,RDD构建。DataFrame是一种以RDD为基础的不可变分布式数据集,DataFrame与RDD的主要区别在于,DF带有schema元信息,数据都被组织到有名字的列中,每一列都带有名称和类型,就像关系型数据库中的表一样,能让spark SQL获取更多的结构信息,对 DF 背后的数据源及作用于 DF 上的变换做针对性优化。反观RDD,由于无从得知 所存数据元素的 具体内部结构,Spark Core只能在stage层面进行简单、通用的流水线优化。
  3. DataSet:和dataFrame差不多,可以把 DataFrame 当作 Dataset[Row] 的别名,每一行的类型是Row;Dataset中,每一个record存储的是一个强类型值而不是Row,每一行是什么类型是不一定的

为什么DataFrame和DataSet比RDD快

因为 DataFrame 和 Dataset API 都是基于 Spark SQL 引擎构建的,它使用 Catalyst 来生成优化后的逻辑和物理查询计划,数据以二进制形式存储,不需要反序列化就能进行sort、shuffle等操作,在需要序列化的时候,spark可以理解 Dataset 类型的 JVM 对象,可以高效地将JVM 对象序列化或反序列化,同时生成压缩字节码,提高执行效率。

RDD 无论是集群间的通信,还是IO操作都需要对对象的结构和数据进行序列化和反序列化,RDD API是函数式的,强调不变性,在大部分场景下倾向于创建新对象而不是修改老对象,会创建大量临时对象,频繁的创建和销毁对象,增加GC,而Spark SQL在框架内部已经在各种可能的情况下尽量重用对象。

15、RDD弹性体现在哪些方面

  1. 自动进行内存和磁盘切换
  2. 基于lineage的高效容错
  3. task如果失败会特定次数的重试
  4. stage如果失败会自动进行特定次数的重试,而且只会只计算失败的分片
  5. checkpoint(如果RDD链条比较长,计算比较笨重,就把数据放在硬盘中)

16、Spark有哪几种join、join的实现

spark中:join、rightOuterJoin、leftOuterJoin、fullOuterJoin

spark SQL中:inner 默认、cross笛卡尔、(full、outer、full_outer)全外连接、(left、left_outer)左外连接、right、right_outer 、left_semi、left_anti

join的实现:

总体上来说,Join的基本实现为,Spark将参与Join的两张表抽象为流式遍历表(streamIter)和查找表(buildIter),通常streamIter为大表,buildIter为小表,spark会基于streamIter来遍历,每次取出streamIter中的一条记录rowA,根据Join条件计算keyA,然后根据该 keyA 去 buildIter 中查找所有满足Join条件(keyB==keyA)的记录 rowBs,并将rowBs中每条记录分别与 rowA join得到 join 后的记录。

  1. sort merge join:分别对 streamIter 和 buildIter 进行排序,在遍历streamIter时,对于每条记录,都采用顺序查找的方式从 buildIter 查找对应的记录,每次处理完 streamIter 的一条记录后,对于streamIter的下一条记录,只需从 buildIter 中上一次查找结束的位置开始查找,不必从头找
  2. broadcast join:如果 buildIter 是一个非常小的表,直接将buildIter广播到每个计算节点,直接在一个map中完成 join,也叫map join
  3. hash join:将来自buildIter的记录放到 hash表 中,加快查找,默认hash join的实现是关闭状态

17、Spark join算子可以用什么替代

可以用广播变量 + map,将小的那个RDD作为广播变量,在另一个RDD中进行遍历,如果broadcast的key和当前RDD的key一样,就进行join

18、Spark shuffle原理

spark shuffle的定义

程序运行的时候,Driver和Executor进程相互交互,分配Task到Executor,Driver 跟 Executor 进行网络传输通知任务数据从哪儿获取,即Task要从 Driver 抓取其他上游的 Task 的数据结果,其中,下一个 Stage 向上一个 Stage 要数据这个过程,我们就称之为 Shuffle。

HashShuffle(未优化)

shuffle write:在一个stage结束计算之后,为了下一个stage可以执行shuffle类的算子,而将每个 task 处理的数据按 key 进行分类,执行hash算法,从而将相同key都写入一个bucket缓存,最后刷新到磁盘,而每一个磁盘文件都只属于下游stage的一个task。在将数据写入磁盘之前,会先将数据写入内存缓冲中,当内存缓冲填满之后,才会溢写到磁盘文件中去。然后ShuffleMapTask将输出发送到DAGScheduler告知每一个ResultTask要拉取的数据的位置和大小。

shuffle read:每个task只要从上游stage的所有task所在节点上,拉取属于自己的那一个磁盘文件即可,一边拉取一边聚合。每个shuffle read task都有一个自己的buffer缓冲,每次都只能拉取与buffer缓冲相同大小的数据,然后通过内存中的一个Map进行聚合等操作。聚合完一批数据后,再拉取下一批数据,并放到buffer缓冲中进行聚合操作。

HashShuffle(优化后)

task不为下游stage的每个task创建一个磁盘文件了,后面的task会复用之前的task的文件,可以有效将多个task的磁盘文件进行一定程度上的合并,从而大幅度减少磁盘文件的数量。

Sort-Base Shuffle

task运行结果的数据会先写入一个内存数据结构中,根据不同的shuffle算子,可能选用不同的数据结构(可能Array-join或map-reduceByKey)。每写一条数据后,判断是否到阈值,达到阈值则溢写磁盘,在溢写之前,先根据key进行排序,排序之后分批写磁盘。

task写入过程中会有多次溢写,也就会产生多个临时文件。最后会将之前所有的临时磁盘文件都进行合并,由于一个task就只对应一个磁盘文件,也就意味着该task为下游stage的task准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个task的数据在文件中的start offset与end offset,在下一个stage的shuffle read task拉取自己的数据时,只要根据索引读取每个磁盘文件中的部分数据即可。

19、Spark shuffle类算子

distinct、intersection、subtract、subtractByKey、join、leftOuterJoin
reduceByKey、groupBy、groupByKey、aggregateByKey、combineByKey
sortBy、sortByKey、coalesce、repartition等。

20、block和partition的关系

  1. block位于hdfs的存储空间、partition 位于spark的计算空间
  2. block的大小固定、partition 大小不固定的(RDD是由分布在各个节点上的partition 组成的,同一RDD的partition 大小不一,数量不定)
  3. block是有冗余的、不会轻易丢失,partition(RDD)没有冗余设计,丢失之后重新计算得到

21、reduceByKey和groupByKey的区别

reduceByKey是更优的算子,会进行map-side预聚合,一个节点上同一个key的数据会被聚合成一条,类似于MapReduce的combiner,传输的时候减小磁盘IO和网络开销,而groupByKey不会聚合,一个key有多少条记录就发送多少条。

22、repartition和coalease的区别

  1. repartition底层调用的就是coalease,shuffle参数为true
  2. coalease的shuffle参数默认为false,所以更快,1000个分区减少为100个,不会产生shuffle

23、为什么划分宽窄依赖

窄依赖以pipeline管道形式顺序执行多条命令,分区内的计算收敛,不需要依赖所有分区的数据,可以并行地在不同节点进行计算。失败时只需要计算丢失的parent partition。

宽依赖需要所有的父分区都是可用的,失败恢复时,宽依赖牵涉RDD各级的多个parent partition。

24、SparkSession和SparkContext

  1. SparkSession是Spark 2.0引入的,为用户提供了统一的切入点使用Spark 各项功能。早期版本中,SparkContext是主要切入点,通过sparkcontext来创建和操作RDD。对于sql,使用sqlContext;对于Hive,使用hiveContext
  2. SparkContext:随着DataSet和DataFrame的API逐渐成为标准API,引入SparkSession作为DataSet和DataFrame API的切入点,SparkSession封装了SparkConf、SparkContext和SQLContext,HiveContext上可用的API在SparkSession上同样可用。与 Spark 交互时不需要显示建 SparkConf, SparkContext 以及 SQlContext

25、Spark广播变量和累加器

  1. 广播变量:如果没有广播变量,则由driver向每个task分发,在task数目十分多的情况下Driver的带宽会成为系统的瓶颈,而且会大量消耗task服务器上的资源,如果用broadcast,driver向executor发一份,在这个executor上启动的task会共享这个变量,节省通信成本和服务器资源。
  2. 累加器:记录符合某特性的数据的数目时,要用到计数器,不被声明为累加器,就不会在driver端进行全局汇总,task运行的是副本,不会改变原始变量的值,使用累加器后,具有分布式计数功能

26、hashpartitioner与rangePartitioner的实现

  1. hashpartitioner:Key.hashCode % partitionNum;如果值为负数,那么就加上partitionNum
  2. rangePartitioner:hashpartitioner的key是随机的,很难进行排序,RangePartitioner能保证各个Partition间的Key是有序的,并且各个Partition间数据量差不多,不保证单个Partition内Key的有序性。
    RangePartitioner将一定范围内的Key映射到某一个分区内,使用水塘抽样算法划分各个partition的key的范围
    第一步:先从整个RDD中抽取出样本数据,将样本数据排序,计算出每个分区的最大key值,形成一个Array[KEY]类型的数组rangeBounds
    第二步:判断key在rangeBounds中所处的范围,给出该key值在下一个RDD中的分区id

27、Spark为什么比Hadoop快

  1. shuffle过程中Hadoop需要落硬盘,spark不一定,可以缓存在内存中,IO少;
  2. Hadoop的task是一个个进程,Spark是一个个线程;
  3. Hadoop容错性低,Spark可以根据RDD之间的血缘关系重算;
  4. Spark有transform和action算子,只有遇到action才会触发job,会做流水线层面的优化;
  5. 多次使用的RDD Spark可以进行缓存

28、Spark常见算子的作用

  1. map:将一个RDD中的每个数据项,通过map中的函数映射变为一个新的元素,有多少个输入分区,就有多少个输出分区
  2. flatmap:Transformation算子,第一步和map一样,最后将所有的输出分区合并成一个分区,flatMap会将字符串看成是一个字符数组,并不会把Array[String]也扁平化成字符数组
  3. glom:将RDD中每一个分区中类型为T的元素转换成Array[T](如果都是int得到一个int数组)
  4. mapPartitions:和map函数类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器(一次处理一个分区),如果在映射的过程中需要频繁创建额外的对象(如创建数据库连接),使用mapPartitions要比map高效
  5. mapPartitionsWithIndex(可用来统计每个分区中的元素和数量):函数作用同mapPartitions,第一个参数为分区的索引
  6. randomSplit:该函数根据weights权重,将一个RDD切分成多个RDD,weights权重指一个Double数组,数组中有几个数,最后就得到几个RDD,权重和为1,原RDD按权重划分。最后得到的是一个RDD数组
  7. union:简单的将两个RDD累加起来,不去重
  8. cartesian:求笛卡尔积
  9. grouBy:接收一个函数,这个函数返回值作为key,然后通过这个key来对里面的元素进行分组
  10. coalesce:用于将RDD进行重分区,使用HashPartitioner,第一个参数为重分区的数目,第二个为是否进行shuffle,默认为false
  11. repartition:该函数其实就是coalesce函数第二个参数为true的实现
  12. distinct:去重
  13. intersection:返回两个RDD的交集,并且去重,可以指定返回的RDD的分区数,分区函数
  14. filter:过滤
  15. subtract:rdd1.subtract(rdd2,num),返回在rdd1中出现,在rdd2中未出现的元素,不去重,num为返回RDD的分区数
  16. sample:采样,withReplacement为true时,允许采样重复值
  17. takeSample:不使用相对比例采样,而是按设定的采样个数进行采样,返回一个Array[T],仅在预期结果数组很小的情况下使用,因为所有数据都被加载到driver的内存中
  18. cache:懒执行的,需要Action算子触发才能执行,底层调用了persist
  19. persist:是懒执行的。必须action类算子触发执行,可以指定缓存级别,默认为MEMORY_ONLY
  20. repartitionAndSortWithinPartitions:在给定的partitioner内部进行排序,性能比repartition要高
  21. mapValues:同基本转换操作中的map,只不过mapValues是针对[K,V]中的V值进行map操作
  22. flatMapValues:同flatMap,只不过flatMapValues是针对[K,V]中的V值进行flatMap操作
  23. sortBy:将RDD中的元素进行排序,默认升序。(可以指定排序规则,按元素本身或按元素的key或value等)
  24. sortByKey:作用于Key-Value形式的RDD,对Key进行排序。该函数返回的RDD一定是ShuffledRDD类型的,因为对源RDD进行排序,必须进行Shuffle操作
  25. zip:zip函数用于将两个RDD组合成Key/Value形式的RDD,这里默认两个RDD的partition数量以及元素数量都相同,否则会抛出异常
  26. zipPartitions:将多个RDD按照 partition 组合成为新的RDD,该函数需要组合的RDD具有相同的分区数,但对于每个分区内的元素数量没有要求
  27. zipWithIndex:将RDD中的元素和这个元素在RDD中的索引号组合成键/值对(键是元素、值是索引号)
  28. zipWithUniqueId:将RDD中元素和一个唯一ID组合成键/值对(ID生成方案:每个分区中第一个元素的唯一ID值为:该分区索引号;每个分区中第N个元素的唯一ID值为:(前一个元素的唯一ID值) + (该RDD总的分区数))
  29. combineByKey:用于将RDD[K,V]转换成RDD[K,C],这里的V类型和C类型可以相同也可以不同
  30. reduceByKey:将RDD[K,V]中相同K对应的V值根据映射函数来运算。
  31. reduceByKeyLocally:与reduceByKey相同,不过返回的不是RDD,是Map[K,V]
  32. partitionBy:该函数根据partitioner函数生成新的ShuffleRDD,将原RDD重新分区。
  33. cogroup:相当于SQL中的全外关联full outer join,返回左右RDD中的记录,关联不上的为空。(将多个RDD中的同一个key对应的不同的value组合到一起)
  34. subtractByKey:类似subtract,针对key,返回在主RDD中出现,并且不在otherRDD中出现的元素(只看key,不看value)
  35. groupByKey:该函数用于将RDD[K,V]中每个K对应的V值,合并到一个集合Iterable[V]中
  36. foldByKey:用于RDD[K,V]根据 K 将 V 做折叠、合并处理,在每一个分区中,先用zerovalue对一个V进行计算(根据映射函数),即对V进行初始化,再将映射函数作用于之后的
  37. join:只能用于两个RDD之间的关联,如果要多个RDD关联,多关联几次即可
  38. leftOuterJoin:只能用于两个RDD之间的关联
  39. rightOuterJoin:同leftOuterJoin
  40. keys:返回RDD中元素的key,不去重
  41. values:返回RDD中元素的value,不去重
  42. foreach:遍历RDD,将函数应用于每一个元素。如果对RDD执行foreach,只会在Executor端有效,而并不是Driver端(rdd.foreach(println),只会在Executor的stdout中打印出来,Driver端看不到
  43. foreachPartition:和foreach类似,只不过是对每一个分区使用
  44. saveAsTextFile:将RDD以文本文件的格式存储到文件系统中
  45. saveAsSequenceFile:以SequenceFile的文件格式保存到HDFS上
  46. saveAsObjectFile:将RDD中的元素序列化成对象,存储到文件中
  47. count:返回RDD中的元素数量
  48. reduce:根据映射函数f,对RDD中的元素进行二元计算
  49. aggregate:聚合RDD中的元素,第一个函数将每一个分区中 T 类型的元素聚合成 U 类型,再使用第二个函数将每个分区聚合后的 U 类型再聚合,需要设定zeroValue,zeroValue必须为U类型,第一个函数和第二个函数中都会应用zeroValue做初始化
  50. fold:aggregate的简化,将aggregate中的两个函数变为使用一个函数
  51. lookup:用于(K,V)类型的RDD,指定K值,返回RDD中该K对应的所有V值
  52. top:按照默认(降序)或者指定的排序规则,返回前num个元素
  53. collect:将一个RDD转换成数组
  54. takeOrdered:和top类似,只不过以和 top 相反的顺序返回元素
  55. take:用于获取RDD中下标为 0 到输入参数-1 的元素,不排序
  56. first:返回RDD中的第一个元素,不排序
  57. countByKey:用于统计RDD[K,V]中每个K的数量
  58. aggregateByKey:最终返回的类型还是Pair RDD,对应的结果是Key和聚合好的值,返回值的类型不需要和RDD中value的类型一致;而aggregate返回非RDD的结果

大数据岗位校招Spark面试总结相关推荐

  1. 大数据岗位的面试总结

    转载自:大数据岗位的面试总结 本人住在有人间天堂之称的城市,6年多开发经验,最近2年主要在做大数据相关的开发,最近考虑换工作,基本也只考虑大数据相关岗位.目前新工作已经找好,但想分享一下最近面试的失败 ...

  2. Interview:人工智能大数据岗位面试—【数据分析师】的简介、技能、待遇、进阶的详细攻略

    Interview:人工智能&大数据岗位面试-[数据分析师]的简介.技能.待遇.进阶的详细攻略 目录 数据分析师的简介 1.网友经验之谈 数据分析师的待遇 数据分析师的技能 数据分析师进阶 数 ...

  3. 上汽乘用车-大数据岗位面试(失败经历)

    步骤 备注 boss直聘 简历投递给 大数据岗位 专业面试 微信远程面试 面试的是部门最高领导,该领导手下有个博士在带团队. 问了tornado和Django的区别(一个支持异步一个不支持,Djang ...

  4. 大厂大数据岗位面试随笔

    大厂面试简要记录 1.腾讯 2.阿里 1.腾讯 腾讯PCG事业部 大数据开发岗 问题回忆: spark数据分发机制 Hadoop集群高可用机制阐述 Spark Streaming给个具体视频应用场景阐 ...

  5. 字节跳动40W大数据开发岗,面试也不过如此

    有个朋友,上个月准备从 Java 转做大数据,一个月过去了,一份面试都没约到,来问我怎么回事. 我一看简历,期望年薪 40w,深度也不够,要大项目也没有. 我们做大数据的,虽说是薪资高,但门槛也是高, ...

  6. 分析了100份大数据岗位要求,总结出这4点

    分析了100份大数据岗位要求,总结出这4点 随着大数据应用在生产生活中的普及,大数据人才的需求越来越多,据<中国经济的数字化转型:人才与就业>的报告显示,目前我国大数据技术人才缺口超过15 ...

  7. 2017年,这两个大数据岗位一定会火!

    讨论哪个大数据岗位会火之前,我们先来简单的分析一下大数据领域的行情,这里重点说一下当前的情况. 2016年,互联网行业遇到了资本寒冬,抛开大公司不说,一些中小型的公司不断的缩减预算,因为很难融到钱. ...

  8. 大数据工程师职场面试攻略技巧有哪些?

    面试是一个双向选择的过程,面试官在选人,面试者在选公司.而面试者了解这家公司最直接的途径就是通过面试官.如果面试者是个到处抢着要的高手,那你有水平的提问会给这个面试者留下深刻印象,毕竟大家都是喜欢和厉 ...

  9. 第2期:大数据岗位有哪些

    大家好,我是老王随聊,今天和大家讨论的话题--大数据岗位有哪些 目前大数据是一个非常有发展前景的岗位,在IT界薪资待遇也很高,很多人想从事这方面的工作,那下面我们谈谈大数据都有哪些岗位. 欢迎加入老王 ...

最新文章

  1. 《Adobe Illustrator CS6中文版经典教程(彩色版)》—第1课1.8节使用面板菜单
  2. 在shell中变量的赋值有五种方法
  3. Android零基础入门第89节:Fragment回退栈及弹出方法
  4. c语言基础傅里叶变换,急求:C语言如何实现快速傅里叶变换
  5. 织梦dedecms search.php注入漏洞exp,DedeCms V57 plus/search.php 文件SQL注射0day漏洞
  6. 大于3小于4的整数bleem_[电影点评]3和4之间还有整数吗?疯子数学家发现,只要证明出来就能穿越今天为大家带来一部只要证明3和4之间还有一个整数就能穿越时空的科幻悬疑片《隐匿的数字》 故...
  7. 思路+源码,利用Python破解WIFI密码详解,100M的字典已备好
  8. AndroidStudio安卓原生开发_Activity的启动方法_隐式启动2种方法_activity关闭---Android原生开发工作笔记83
  9. 马云刘强东隔空互怼,美团外卖大范围故障,苹果系统漏洞百出 | 一周业界事
  10. mysql完成字符串分割
  11. 语音识别合成助手-语音识别合成助手下载 v20190223免费版--pc6下载站
  12. 冲刺Two之站立会议4
  13. Eclipse快捷方式无法在桌面上打开
  14. 博客怎么写出好的文章吸引读者,只有7个基本的写作技巧
  15. (附源码)spring boot图书管理系统 毕业设计160934
  16. BUUCTF-WEB 【0CTF 2016】piapiapia 1
  17. 计算机词汇店名,电脑店名字200例
  18. LaTex论文排版 | (23) LaTex中的正上、正下标记以及各种箭头符号总结
  19. WPS文字表格外计算功能配合书签使用公式轻松实现
  20. 机器学习实践——支持向量机

热门文章

  1. Java 下载远端图片到本地
  2. wordpress子比zibll主题V6.4.1免授权博客自媒体付费下载主题
  3. 从乡土走向国际,江小白的背后暗藏了哪些玄机?
  4. linux I2C驱动架构解析
  5. Android渣本毕业四年,面试小厂面试官说我可以试试大厂
  6. vue x 兼容iphone_详解关于移动端兼容iPhoneX底部小黑条
  7. centos 清理磁盘空间 及 内存占用,docker容器优化清理
  8. 计算机视觉基础(六)——图像边缘检测
  9. H5移动端适配 rem 和 vw 的区别
  10. 使用Zxing玩转二维码白边的各个花样