RICH-ATONE

大数据高频面试题

面试中的问题(重点)**

1. RDD的特性(RDD的解释)
1.RDD可以看做是一些列partition所组成的
2.RDD之间的依赖关系
3.算子是作用在partition之上的
4.分区器是作用在kv形式的RDD上
5.partition提供的最佳计算位置,利于数据处理的本地化即计算向数据移动而不是移动数据
ps:RDD本身是不存储数据,可以看做RDD本身是一个引用数据
RDD弹性
1) 自动进行内存和磁盘数据存储的切换
Spark优先把数据放到内存中,如果内存放不下,就会放到磁盘里面,程序进行自动的存储切换
2) 基于血统的高效容错机制
在RDD进行转换和动作的时候,会形成RDD的Lineage依赖链,当某一个RDD失效的时候,可以通过重新计算上游的RDD来重新生成丢失的RDD数据。
3) Task如果失败会自动进行特定次数的重试
RDD的计算任务如果运行失败,会自动进行任务的重新计算,默认次数是4次。
4) Stage如果失败会自动进行特定次数的重试
如果Job的某个Stage阶段计算失败,框架也会自动进行任务的重新计算,默认次数也是4次。
5) Checkpoint和Persist可主动或被动触发
RDD可以通过Persist持久化将RDD缓存到内存或者磁盘,当再次用到该RDD时直接读取就行。也可以将RDD进行检查点,检查点会将数据存储在HDFS中,该RDD的所有父RDD依赖都会被移除。
6) 数据调度弹性
Spark把这个JOB执行模型抽象为通用的有向无环图DAG,可以将多Stage的任务串联或并行执行,调度引擎自动处理Stage的失败以及Task的失败。
7) 数据分片的高度弹性
可以根据业务的特征,动态调整数据分片的个数,提升整体的应用执行效率。



2. RDD的两类算子
RDD编程API
RDD支持两种操作:转化操作和行动操作。RDD 的转化操作是返回一个新的 RDD的操作,比如 map()和 filter(),而行动操作则是向驱动器程序返回结果或把结果写入外部系统的操作。比如 count() 和 first()。
Spark采用惰性计算模式,RDD只有第一次在一个行动操作中用到时,才会真正计算。Spark可以优化整个计算过程。默认情况下,Spark 的 RDD 会在你每次对它们进行行动操作时重新计算。如果想在多个行动操作中重用同一个 RDD,可以使用 RDD.persist() 让 Spark 把这个 RDD 缓存下来。
3.25.17 Transformation算子(重要)
RDD中的所有转换都是延迟加载的,也就是说,它们并不会直接计算结果。相反的,它们只是记住这些应用到基础数据集(例如一个文件)上的转换动作。只有当发生一个要求返回结果给Driver的动作时,这些转换才会真正运行。这种设计让Spark更加有效率地运行。
转换 含义
map(func) 返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成
filter(func) 返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成
flatMap(func) 类似于map,但是每一个输入元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素)
mapPartitions(func) 类似于map,但独立地在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]
mapPartitionsWithIndex(func) 类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是(Int, Iterator[T]) => Iterator[U]
sample(withReplacement, fraction, seed) 根据fraction指定的比例对数据进行采样,可以选择是否使用随机数进行替换,seed用于指定随机数生成器种子
union(otherDataset) 对源RDD和参数RDD求并集后返回一个新的RDD
intersection(otherDataset) 对源RDD和参数RDD求交集后返回一个新的RDD
distinct([numTasks])) 对源RDD进行去重后返回一个新的RDD
groupByKey([numTasks]) 在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD
reduceByKey(func, [numTasks]) 在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置
aggregateByKey(zeroValue)(seqOp, combOp, [numTasks]) 相同的Key值进行聚合操作,在聚合过程中同样使用了一个中立的初始值zeroValue:中立值,定义返回value的类型,并参与运算seqOp:用来在同一个partition中合并值combOp:用来在不同partiton中合并值
sortByKey([ascending], [numTasks]) 在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD
sortBy(func,[ascending], [numTasks]) 与sortByKey类似,但是更灵活
join(otherDataset, [numTasks]) 在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD
cogroup(otherDataset, [numTasks]) 在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable<V>,Iterable<W>))类型的RDD
cartesian(otherDataset) 笛卡尔积
pipe(command, [envVars]) 将一些shell命令用于Spark中生成新的RDD
coalesce(numPartitions) 重新分区
repartition(numPartitions) 重新分区
repartitionAndSortWithinPartitions(partitioner) 重新分区和排序
3.25.18 Action算子(重要)
在RDD上运行计算,并返回结果给Driver或写入文件系统
动作 含义
reduce(func) 通过func函数聚集RDD中的所有元素,这个功能必须是可交换且可并联的
collect() 在驱动程序中,以数组的形式返回数据集的所有元素
count() 返回RDD的元素个数
first() 返回RDD的第一个元素(类似于take(1))
take(n) 返回一个由数据集的前n个元素组成的数组
takeSample(withReplacement,num, [seed]) 返回一个数组,该数组由从数据集中随机采样的num个元素组成,可以选择是否用随机数替换不足的部分,seed用于指定随机数生成器种子
takeOrdered(n, [ordering]) takeOrdered和top类似,只不过以和top相反的顺序返回元素
saveAsTextFile(path) 将数据集的元素以textfile的形式保存到HDFS文件系统或者其他支持的文件系统,对于每个元素,Spark将会调用toString方法,将它装换为文件中的文本
saveAsSequenceFile(path) 将数据集中的元素以Hadoop sequencefile的格式保存到指定的目录下,可以使HDFS或者其他Hadoop支持的文件系统。
saveAsObjectFile(path)
countByKey() 针对(K,V)类型的RDD,返回一个(K,Int)的map,表示每一个key对应的元素个数。
foreach(func) 在数据集的每一个元素上,运行函数func进行更新。



3. 算子原理(shuffle算子原理,引出Shuffle原理)
4. Shuffle原理(和Hadoop的shuffle区别)
shuffle是发生在map和refuce之间,是map和reduce之间的桥梁,他是将一些无规律的数据转变为有规律的数据的过程,map从数据端拉去数据,经过排序和合成后 存入系统磁盘,reduc端从map端磁盘读取处理好的数据进行排序分组的过程
spark shuffle是spark所使用的hashshuffle
没有优化前的hashbuffle是每个一个executor存在多个maptask,每个maptask都会产生多个
bucket文件,reduce将这些bucket进行分组,这样存在大量的bucket,读写麻烦,分组慢,影响系统效率
优化一次后的shuffle(1.6-2.0版本)是将maptask后的bucket进行分组,然后在通过reduce再次处理,虽然简化了bucket的数目,但是仍存在很多的小文件
三、Sort-Based Shuffle
为了缓解Shuffle过程产生文件数过多和Writer缓存开销过大的问题,spark引入了类似于hadoop Map-Reduce的shuffle机制。该机制每一个ShuffleMapTask不会为后续的任务创建单独的文件,而是会将所有的Task结果写入同一个文件,并且对应生成一个索引文件。以前的数据是放在内存缓存中,等到缓存数据读取完了再刷到磁盘,现在为了减少内存的使用,在内存不够用的时候,可以将输出溢写到磁盘。结束的时候,再将这些不同的文件联合内存的数据一起进行归并,从而减少内存的使用量。一方面文件数量显著减少,另一方面减少Writer缓存所占用的内存大小,而且同时避免GC的风险和频率。

Sort-Based Shuffle有几种不同的策略:BypassMergeSortShuffleWriter(Bypass机制)、SortShuffleWriter(普通机制)和UnsafeShuffleWriter。

对于BypassMergeSortShuffleWriter,使用这个模式的特点为:
# 主要用于处理不需要排序和聚合的Shuffle操作,所以数据是直接写入文件,数据量较大的时候,网络I/O和内存负担较重。
# 主要适合处理Reducer任务数量比较少的情况。
# 将每一个分区写入一个单独的文件,最后将这些文件合并,减少文件数量。但是这种方式需要并发打开多个文件,对内存消耗比较大。
因为BypassMergeSortShuffleWriter这种方式比SortShuffleWriter更快,所以如果在Reducer数量不大,又不需要在map端聚合和排序,而且Reducer的数目小于spark.shuffle.sort.bypassMergeThreshold指定的阀值(默认200)时,就是用的是这种方式(即启用条件)。

对于SortShuffleWriter,使用这个模式的特点为:
# 比较适合数据量很大的场景或者集群规模很大。
# 引入了外部排序器,可以支持在Map端进行本地聚合或者不聚合。
# 如果外部排序器enable了spill功能,如果内存不够,可以先将输出溢写到本地磁盘,最后将内存结果和本地磁盘的溢写文件进行合并。
另外,这个Sort-Based Shuffle跟Executor核数没有关系,即跟并发度没有关系,它是每一个ShuffleMapTask都会产生一个data文件和index文件,所谓合并也只是将该ShuffleMapTask的各个partition对应的分区文件合并到data文件而已。所以这个就需要和Hash-BasedShuffle的consolidation机制区别开来。
对于UnsafeShuffleWriter由于需要谨慎使用,我们暂不做分析。

shuffle调优
1. 合并map输出文件,开启输出文件合并机制 spark.shuffle.consolidateFiles 2. 调节map内存缓冲 spark.shuffle.file.buffer 和reduce内存占比 spark.shuffle.memoryFraction,0.2
3. shufflemananger选择

5. 检查点、持计划、共享变量
https://blog.csdn.net/wjn19921104/article/details/80268661
6. 分区(自定义分区、默认分区,区别,作用)

7. 并行度(跑任务的并行度)参考调优文档1.2.3


8. Spark的任务运行原理(重点中的重点)

9. Task原理(本地化级别)
1.概念:task在执行前都会获取数据的分区信息进行分配,总是会优先将其分配到它要计算的数据所在节点,尽可能的减少网络传输
2.过程:一般会默认3s,重试5次的去分配,一旦超时失败,将会选择一个比上一个本地级别差的级别再一次分配,如果发生了数据传输,那么task首先通过blockmanager获取数据,如果本地没有数据,则通过getRemote方法从数据所在节点的blockmanager获取数据并返回至task所在节点
3.级别
PROCESS_LOCAL:进程本地化,性能最好。指代码和数据在同一个进程中,也就是同一个executor 中;计算数据的task由executor执行,此时数据在executor的blockmanager里
NODE_LOCAL:节点本地化。代码和数据在同一个节点中,数据存储为节点的hdfs block数据块,
task在节点的某个executror执行;或者数据和task在同一个节点不同的executor中,数据需要跨进程传输
NO_PREF:数据从哪里获取都一样,比如从数据库中获取数据,对于task而言没有区别
RACK_LOCAL:数据和task在一个机架的两个节点上,数据需要通过网络在节点之间进行传输
ANY:数据和task可能在集群中的任何地方,而且不在一个机架中,性能最差
4.调节:spark.locality.wait参数默认是3s,默认情况下,以下几个参数都是以 spark.locality.wait为默认值, spark.locality.wait.process spark.locality.wait.node spark.locality.wait.rack
实际情况中通过调节不同值达到最优的计算分配效果

10. DAG的原理(源码级别)
那么在划分Stage的时候,会通过createResultStage方法创建一个ResultStage,然后根据方法 getShuffleDependencies递归推导,其原理是将最后一个rdd放入站中,判断他和其父rdd的关系,如果是shuffle,那么就划分ShuffleMapStage,如果没有就将其父节点入站继续往前推,直至切分出所有的依赖,生成一个宽依赖集合,然后交给getOrCreateShuffleMapStage方法生成stage,实现所有的Stage的划分,最后通过submitStage方法中的getMissingParentStages方法递归寻找所有stage(类似rdd划分),通过submitStage方法中的submitMissingTasks方法将stage封装为 task

11. SparkSQL和Hive区别

Ps: https://www.cnblogs.com/lixiaochun/p/9446350.html
12. DF和DS的之间的关系(从它的类型出发)
DataFrame是弱类型,是抽象数据集,Rdd和Schema的集合,可以像二维表一样操作
DataSet:属于DataFrame的父类,DataFrame=Dataset[row],强类型

13. 窗口函数(排名函数)
rank()跳跃排序,有两个第二名时后边跟着的是第四名 dense_rank() 连续排序,有两个第二名时仍然跟着第三名 over()开窗函数:
在使用聚合函数后,会将多行变成一行,而开窗函数是将一行变成多行;
并且在使用聚合函数后,如果要显示其他的列必须将列加入到group by中, 而使用开窗函数后,可以不使用group by,直接将所有信息显示出来。
开窗函数适用于在每一行的最后一列添加聚合函数的结果。
常用开窗函数:
1.为每条数据显示聚合信息.(聚合函数() over())
2.为每条数据提供分组的聚合函数结果(聚合函数() over(partition by 字段) as 别名)
--按照字段分组,分组后进行计算
3.与排名函数一起使用(row number() over(order by 字段) as 别名) 常用分析函数:(最常用的应该是1.2.3 的排序)
1、row_number() over(partition by ... order by ...) 2、rank() over(partition by ... order by ...)
3、 dense_rank() over(partition by ... order by ...)
4、 count() over(partition by ... order by ...)
5、 max() over(partition by ... order by ...)
6、 min() over(partition by ... order by ...)
7、 sum() over(partition by ... order by ...)
8、 avg() over(partition by ... order by ...)
9、 first_value() over(partition by ... order by ...)
10、 last_value() over(partition by ... order by ...)
11、 lag() over(partition by ... order by ...) 12、lead() over(partition by ... order by ...)
lag 和lead 可以 获取结果集中,按一定排序所排列的当前行的上下相邻若干offset 的某个行的某个列(不用结果集的自关联); lag ,lead 分别是向前,向后;
lag 和lead 有三个参数,第一个参数是列名,第二个参数是偏移的offset,第三个参数是 超出记录窗口时的默认值

14. SparkSQL-UDF(自定义函数)



15. SparkStreaming对接Kafka的两种方式(重点)


16. 如何解决数据积压问题(反压机制或者增加分区和消费者)
反压机制:
原因:Spark Streaming在处理不断流入的数据是通过每间隔一段时间(batch interval),将这段时间内的流入的数据积累为一个batch,然后以这个batch内的数据作为job DAG的输入RDD提交新的job运行。当一个batch的处理时间大于batch interval时,意味着数据处理速度跟不上数据接收速度,此时在数据接收端(即Receiver 一般数据接收端都运行在executor上)就会积累数据,而数据是通过BlockManager管理的,如果数据存储采用MEMORY_ONLY模式就会导致OOM,采用 MEMORY_AND_DISK多余的数据保存到磁盘上反而会增加数据读取时间。

参数:
spark.streaming.backpressure.enabled 设置为 true 开启反压 spark.streaming.kafka.maxRatePerPartition 每个partition每秒最多消费条数 spark.streaming.backpressure.rateEstimator 速率估算器类,默认值为 pid ,目前 Spark 只支持这个。


17. 如何保证数据一致性问题(生产者和消费者)



18. Kafka数据传输机制(参考图)

19. Kafka如何保证数据不丢失(消费者)

20. redis数据类型·

21. redis的持久化
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。
RDB是Redis默认采用的持久化方式,在redis.conf配置文件中默认有此下配置: save 900 1
通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。

22. redis的击穿和雪崩(参考面试宝典,最下面)

23. redis的集群原理(集群实现需要注意什么)


24. SparkStreaming累加操作(参考UpdateStateBykey和MapwithState)
https://blog.csdn.net/zhanglh046/article/details/78505124
https://www.cnblogs.com/yinpin2011/p/5539708.html
25. ForeachRDD和Transform的区别


26. 算子的区别(MapPartitions和Map或者foreach和foreachPartition区别)


27. 什么是DStream
Spark Streaming概述
Spark Streaming类似于Apache Storm,用于流式数据的处理。根据其官方文档介绍,Spark Streaming有高吞吐量和容错能力强等特点。Spark Streaming支持的数据输入源很多,例如:Kafka、Flume、Twitter、ZeroMQ和简单的TCP套接字等等。数据输入后可以用Spark的高度抽象原语如:map、reduce、join、window等进行运算。而结果也能保存在很多地方,如HDFS,数据库等。另外Spark Streaming也能和MLlib(机器学习)以及Graphx完美融合。
DStream的概念
Discretized Stream是Spark Streaming的基础抽象,代表持续性的数据流和经过各种Spark原语操作后的结果数据流。在内部实现上,DStream是一系列连续的RDD来表示。每个RDD含有一段时间间隔内的数据,如下图:
DStream原语类型介绍(重要)
DStream上的原语与RDD的类似,分为Transformations(转换)和Output Operations(输出)两种,此外转换操作中还有一些比较特殊的原语,如:updateStateByKey()、transform()以及各种Window相关的原语。
详解:见Spark Streaming课件


28. 调优文档(参考Spark调优)
29. 数据倾斜解决方案(参考Spark内核解析和调优指南)
30. JVM调优(参考Spark调优文档)
31. GC垃圾回收机制(算法原理)
32. 手写快排或者其他算法(基础算法)
33. Spark的内存模型
34. 手写单例模式 hadoop
1. HDFS文件存储机制(读写流程)


2. MR的原理(Map和Reduce) 3. Shuffle原理
4. Hive的内部和外部表
5. Hive的动态分区
6. hive分区分桶
7. Hive和Mysql区别 8. Hive和Hbase区别
9. Hive的调优(参考面试宝典)



10. HBASE的热点问题(什么时候会触发,如何避免)
一、 出现热点问题原因
1、 hbase的中的数据是按照字典序排序的,当大量连续的rowkey集中写在个别的region,各个region之间数据分布不均衡;
2、 创建表时没有提前预分区,创建的表默认只有一个region,大量的数据写入当前 region;
3、 创建表已经提前预分区,但是设计的rowkey没有规律可循,设计的rowkey应该由 regionNo+messageId组成

二、 解决方案加盐
这里所说的加盐不是密码学中的加盐,而是在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同。分配的前缀种类数量应该和你想使用数据分散到不同的 region的数量一致。加盐之后的rowkey就会根据随机生成的前缀分散到各个region上,以避免热点。
哈希
哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据反转
第三种防止热点的方法时反转固定长度或者数字格式的rowkey。这样可以使得rowkey中经常改变的部分(最没有意义的部分)放在前面。这样可以有效的随机rowkey,但是牺牲了rowkey的有序性。
反转rowkey的例子以手机号为rowkey,可以将手机号反转后的字符串作为rowkey,这样的就避免了以手机号那样比较固定开头导致热点问题时间戳反转
一个常见的数据处理问题是快速获取数据的最近版本,使用反转的时间戳作为rowkey的一部分对这个问题十分有用,可以用 Long.Max_Value - timestamp 追加到key的末尾,例如 [key]
[reverse_timestamp] , [key] 的最新值可以通过scan [key]获得[key]的第一

11. Hbase的原理(读取和存储)


12. HbaseRowKey设计原理
1.RowKey长度原则,最大长度为64KB,一般设计成定长。建议是越短越好,不要超过16个字节,过长占用HFile和内存空间
2.RowKey散列原则:如果RowKey是按时间戳的方式递增,不要将时间放在二进制码的前面,建议将
RowKey的高位作为散列字段,由程序循环生成,低位放时间字段,
3.RowKey唯一原则:必须在设计上保证其唯一性。RowKey是按照字典排序存储的,要充分利用这个排序特点,将经常一起读取的数据存储到一块,将最近可能会被访问的数据放在一块。

13. Hbase和其他数据库相比的优势(特点)


14. Flume的Source源有哪些


15. Flume高可用(怎么实现高可用)


16. Linux命令、HDFS命令(基础命令)
17. Zookeeper的选举机制(内部如何实现)
18. Oozie和Azkaban区别(主要是配置)
19. 布隆过滤器(原理)


掌握一到两种算法(原理)

需要掌握的事情
1. 项目架构:所有的
2. 项目流程:数据走向,数据处理时候的指标
3. 项目人员搭配
4. 项目的数据量
5. 项目的问题 kafka问题 居多(数据一致性,数据完整性,分区动态扩容,数据积压,kafka吞吐量) sparkStreaming问题(批次数据量,批次间隔 ,job等待)
6. 集群规模 (实现高可用)
7. 项目描述

posted on 2019-09-10 14:40  RICH-ATONE  阅读(974)  评论(0编辑  收藏  举报

导航