这里是自己搜集到的面试真题,主要是大厂应届/暑期实习的数据开发、数据仓库岗位,为面试做准备,分享出来给大家一起学习,大家面试有遇到什么问题这里面没有的,也可以在评论区分享一下,我会整理答案放进来。
Hadoop主要解决海量数据的存储和分析计算,包括了HDFS、MapReduce、Yarn。
9.3 大表 Join 大表(10 亿级别的,比如订单 Join 商品表)可能有一些商品销量特别好,数据倾斜,要如何解决?
1.常用端口
- 9870:namenode的web端口
- 9864:datanode的web端口
- 8088:yarn的web端口
- 19888:历史服务器的web端口
2.常用配置文件
- core-site.xml
- hdfs-site.xml
- yarn-site.xml
- mapred-site.xml
- works
3.HDFS
分布式文件存储系统
3.1 HDFS架构
- NameNode(NN)管理元数据,与客户端交互
- DataNode(DN)存储实际的数据,执行读写操作
- SecondaryNameNode(2NN)辅助NN
3.2 HDFS读取流程
- 客户端client向NN发送请求下载文件
- NN查询元数据找到文件块所在DN节点地址(多个副本地址),返回给客户端
- 客户端就近原则选取DN节点请求读取数据
- DN发送数据给客户端
3.3 HDFS写入流程
- 客户端client向NN发送请求上传文件
- NN按照机架感知策略,返回存储Block和其副本的DN节点,默认3个副本
- 客户端根据获取的DN节点,逐个请求上传Block,直至传完
3.4 机架感知原理
- 文件block的第一个副本,存放在客户端链接的服务器节点上,客户端不在集群内则随机选一个节点
- 第二个副本,在另一个机架的随机节点
- 第三个副本,在第二个副本所在机架的其他随机节点
- 更多副本随机节点存储
3.5 nn和2nn的联系与区别
- nn负责管理文件系统的元数据、与客户端交互
- 2nn不是nn的热备份,2nn 定期触发CheckPoint,代替nn合并编辑日志EditLog和镜像文件Fsimage,减少nn的工作,通常一小时一次。
- nn发生故障,可以从2nn恢复历史数据
3.6 镜像文件和编辑日志
- 镜像文件Fsimage:是元数据的永久检查点,包含文件目录和序列化信息
- 编辑日志EditLog:存放文件所有的更新操作
- Fsimage和EditLog合并:就是元数据的最新信息,每当NameNode启动时,读取镜像文件,并加载编辑日志中的文件更新操作,以此获得最新的元数据。
3.7 HDFS文件块Block
- HDFS文件在物理上是分块存储的,块的大小取决于磁盘的传输速度,默认128M
- 块太大:磁盘传输速度慢
- 块太小:寻址时间太长
- 分块目的:减少MapReduce程序执行时等待文件的读取时间,HDFS支持大文件存储,如果文件过大10G不分块,在处理数据时就会大量的将时间耗费在读取文件中,分块可以配合MapReduce程序的切片操作,减少程序的等待时间。
3.8 心跳检测
- DataNode向NameDode每3秒发送一次心跳,NameNode返回需要执行的指令。
- 如果超过一定时间(10分钟+10次心跳)没有收到心跳,则认为DN节点不可用
3.9 HDFS的小文件问题
背景:每个文件均按Block块存储,每个块的元数据都会存储在NameNode的内存中,大量的小文件会消耗大量NameNode的内存,因此HDFS存储小文件会非常低效。
产生问题:
-
大量小文件会占用NameNode大量内存来存储文件目录和块信息(元数据)。
-
大量小文件会导致文件的寻址时间过长,超过读取时间,违反了HDFS的设计目标。
-
计算过程中,每个小文件都会起一个MapTask,1 个 MapTask 默认内存 1G,这会浪费大量资源。
解决方法:
- 数据采集或者标准入库前,将小文件合并成大文件再传入HDFS。
- 使用Hadoop Archive归档,将多个小文件打包成一个HAR大文件。
- 计算过程,输入数据接口使用CombineTextInputFormat进行处理,可以把多个小文件合并成一个切片处理,减少启动的MapTask数量。
- 写一个MR程序进行小文件合并。
- 有小文件场景开启 JVM 重用;如果没有小文件,不要开启 JVM 重用,因为会一 直占用使用到的 Task 卡槽,直到任务完成才释放。(JVM 重用可以使得 JVM 实例在同一个 job 中重新使用 N 次)
4. MapReduce
分布式计算框架
4.1 核心思想
- 先拆分,再合并
- 先Map,再Reduce,都是并发执行
4.2 MR工作流程
Maptask
- Read阶段:将输入的数据进行分片操作,一个split对应一个Maptask,大小默认是block大小;并通过inputformat将split格式化为键值对的形式,key表示偏移量,value表示每一行内容。
- Map阶段:那个maptask都有一个环形缓冲区,输入的数据通过map()函数执行业务逻辑操作,并写入环形缓冲区,数据达到缓冲区阈值80%(80M)就开始溢出,剩下20%继续接收数据。
- Spill阶段:数据溢出写入磁盘中临时文件
- Merge阶段:当所有数据处理完成后,MapTask对所有临时文件进行一次合并,以确保一个Maptask最终只会生成一个数据文件。
Shuffle的作用是将MapTask输出的处理结果数据,分发给ReduceTask,并在分发的过程中,对数据按key进行分区和排序。
- 分区排序:数据溢出写入磁盘前,会进行分区和排序,按照key的哈希值对Reducetask个数取模进行分区,一个分区对应一个ReduceTask,分区内部对key值按照字典顺序进行快速排序;(排序可以使Reduce任务更加高效地执行某些操作,比如二分查找,归并排序都是基于有序数据)
- 局部聚合:如果用户设置了Combiner,则写入文件之前,对每一个MapTask的输出进行局部汇总(相当于小的reducer),以减少网络传输量。(如wordcount中,将Hello 1,Hello 1合并成Hello 2)。
- 归并排序:当数据溢写完毕后,每个MapTask会对所有溢写文件进行归并排序,并合并(merge)输出为一个文件。
- 压缩:压缩数据,以减少网络传输量。
- 将数据写入磁盘,等待Reducer拉取数据。
- Reducer按照分区拉取每个Maptask输出文件对应分区的数据,优先放入内存,内存不够再溢出到磁盘。
- 归并排序:当所有数据拷贝完毕后,ReduceTask对所有数据进行一次归并排序。
- 分组:按照相同的Key值索引进行分组。
- 执行Reduce逻辑操作
Reducetask
- Copy阶段:Reducer从各个Maptask远程拷贝一片数据,优先放入内存,超过一定阈值写入磁盘。
- Sort阶段:数据拷贝过程会对内存和磁盘上的文件进行合并 ,防止内存使用过多或磁盘上文件过多,数据拷贝完成后进行一次归并排序(map阶段进行了快速排序,数据是有序的,所以选择归并排序)
- Reduce阶段:reduce()函数将计算结果写到HDFS上。
4.3 MR进行了几次排序,排序目的
三次排序:
- 环形缓冲区数据溢出写入磁盘前,按照key进行一次快速排序。
- 当数据溢写完毕后,会对多个溢出文件进行一次归并排序。
- 当所有数据拷贝完毕后,每个Reduce Task会对收到的数据进行一次归并排序。
实际上Map阶段的排序就是为了减轻Reduce阶段排序负载。
4.4 Combiner
Combiner的作用是为了减少传输到Reduce中的数据量,减轻Reduce负载。
Combiner相当于一个小的Reduce,作用也是合并,区别在于Combiner 是在每一个 MapTask 所在的节点运行,对MapTask的输出进行局部汇总,以减少网络传输量。
4.5 环形缓冲区的反向如何理解
环形缓冲区主要两部分:一部分写入数据的索引信息,另一部分写入数据的内容。环形缓冲区的默认大小是100M,当缓冲的容量达到默认大小的80%时,开启一个新的线程进行反向溢写,之所以反向溢写,因为这样可以边磁盘溢写数据边往接收数据 ,不需要等待溢写完毕。
5. Yarn
资源任务管理器
5.1 基础架构
- ResourceManager(RM):集群资源管家,整个集群资源的调度者,负责调度各个程序所需的资源:处理客户端请求、监控NodeManager、启动或监控ApplicationMaster
- NodeManager(NM):单机资源管家,单个节点服务器资源的调度者,负责调度单个服务器上的资源提供给应用程序使用:处理ResourceManager命令,处理ApplicationMaster命令
- Container:任务(Task)运行的容器,相当于一台独立的服务器,里面封装了任务运行需要的资源(内存、CPU、磁盘、网络等);
- ApplicationMaster(AM):单个任务运行的老大,为任务/程序申请资源并分配给内部的任务,任务的监控与容错
5.2 Yarn工作流程
- 客户端向ResourceManager提交任务(应用程序)
- ResourceManager接收到任务,通过资源调度器选择一个资源宽裕的NodeManager分配一个容器Container专门用于启动ApplicationMaster,将任务交给AppMaster
- AppMaster启动后,首先向ResourceManager进行注册,然后为各个任务申请资源,并监控运行情况
- AppMaster采用轮询的方式,通过RPC协议向RM申请和领取资源(即创建更多容器用来实际运行任务)
- AppMaster申请到资源后,与NM通信,要求NM启动任务
- NM启动任务,全部任务运行完成后,AppMaster向RM注销自己,释放资源(Container也会回收)
- RPC协议
- 远程过程调用协议,允许一个程序请求另一个程序在远程计算机上执行代码,并等待结果返回
5.3 调度器
Hadoop作业调度器主要有三种:FIFO调度器、容量调度器和公平调度器
- FIFO调度器:先进先出调度器,单队列,根据提交作业的先后顺序,先来先服务。
- 容量调度器:多队列,每个队列设设置资源上下限,队列内部采用FIFO策略,资源盈余的队列可以共享资源给其他队列使用,优先选择资源利用率低的队列。
- 公平调度器:与容量调度器相同,但是调度策略不同,优先选择对资源缺额比例大的队列。
6.数据倾斜
数据倾斜发生在大数据计算引擎(mr,hive,spark,flink),一般都分为map,reduce两个阶段。
定义:数据倾斜就是在计算数据的时候,由于数据分散度不够,导致大量的数据集中到一台或者几台机器上计算,这些数据的计算速度远远低于平均计算速度,导致整个计算过程很慢。
例子:任务长时间维持在99%,查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成,因为其处理的数据量明显大于其他reduce任务。
原因及解决:
map输出数据是按照key进行分区分配到不同的reduce中,key分布不均匀或大量空值,就会导致reducer上的数据差异过大。
- key分布不均匀:存在大量相同值的数据;存在大量异常值或者空值。
- 业务数据本身的特性:某个城市订单量明显多于其他城市,对该城市的订单统计聚合时,容易发生数据倾斜。
- SQL语句导致的数据倾斜:
- 两个表中关联字段存在大量空值(解决方法:去除或者附随机值),或是关联字段的数据不统一(解决方法:把数字类型转为字符串类型,统一大小写)
- join 一个key集中的小表 (解决方法:reduce join 改成 map join,在map端完成join,不会按照key进行分区,数据相对均匀分布到reducer中)
- group by维度过小 某值的数量过多 (解决方法:在Map端预聚合,放粗粒度)
- count distinct 某特殊值过多 (解决方法:采用sum() group by的方式来替换count(distinct)完成计算)
7.集群高可用
所谓高可用集群高可用(High Availability Cluster,简称HA Cluster),即当前服务器出现故障时,可以将该服务器中的服务、资源、IP等转移到另外一台服务器上,从而满足业务的持续性;这两台或多台服务器构成了服务器高可用集群。
Hadoop1.0中存在
- NameNode单点故障,难以应用于在线场景;
- NameNode压力过大,且内存受限,影响系统可扩展性等问题。
Hadoop2.0使用了HDFS HA(high available 高可用)
- 解决单点故障
- HDFSHA: 通过主备NameNode解决单点故障
- 如果主NameNode发生故障,则切换到备NameNode
- 解决内存受限问题
- HDFSFederation(联邦)解决内存受限问题 把数据分为多份,多个NameNode相互独立工作,共享DataNode
- 水平扩展,支持多个NameNode
- 每个NameNode分管一部分目录
- 所有NameNode共享所有DataNode存储资源
8.脑裂问题
在 HA 集群中,脑裂指的是当联系主备节点的“心跳线”断开时(即两个节点断开联系时),本来为一个整体、动作协调的 HA 系统,就分裂成为两个独立的节点。由于相互失去了联系,主备节点之间像“裂脑人”一样,使得整个集群处于混乱状态。脑裂的严重后果:
集群无主
:都认为对方是状态好的,自己是备份角色,后果是无服务;集群多主
:都认为对方是故障的,自己是主角色。相互争抢共享资源,结果会导致系统混乱,数据损坏。此外对于客户端访问也是一头雾水,找谁呢?
避免脑裂问题的核心是:保持任意时刻系统有且只有一个主角色提供服务。
9.场景题
下面这些场景题不一定是Hadoop的内容,比较综合。
9.1 如果某天流量突然变化幅度很大,怎么分析原因
这个感觉像是数据分析的题,不过携程数仓问了这个问题。
1.确认流量真实性,看流量是真实增加,还是某个数据流程环境出现了错误导致的。
2.分析流量来源渠道,看突增的流量从哪个渠道流入的,根据不同渠道的特性进行分析。
3.可能原因:政策原因、推广宣传引流来的、与热点相关导致的、优惠活动......
9.2 有限内存下的一亿数据怎么排序
当需要对大规模数据进行排序时,传统的排序算法(如快速排序、归并排序等)往往无法直接应用,因为它们要求所有数据同时存在于内存中,这种情况下,需要采用外部排序算法来解决这一问题。
外部排序是一种用于处理大型数据集合的排序算法,由于内存限制,无法将整个数据集放入内存中进行排序。因此,外部排序使用磁盘或其他外部存储介质来存储和处理数据。
- 划分阶段: 数据被分割成适当大小的块,每个块可以容纳在内存中进行排序。
- 排序阶段: 每个块在内存中进行排序,常用的排序算法如快速排序、堆排序等。
- 归并阶段: 将所有的块归并到一个文件中。
具体解决方案:
- 切分大文件至多个小文件
- 对每个小文件进行单独排序
- 维护一个优先队列,优先队列的大小为文件数目。
- 将每个小文件的第一个数字和该数字的来源放入优先队列中。
- 将优先队列中的堆顶弹出,堆顶数字即当前最小值,再从数字来源中读入一个新的数字进入优先队列。
- 关闭文件,删除临时文件
9.3 大表 Join 大表(10 亿级别的,比如订单 Join 商品表)可能有一些商品销量特别好,数据倾斜,要如何解决?
数据倾斜问题场景题,大表join大表发生数据倾斜,此时可以看一下两个大表中的key分布情况,一般是因为其中一个大表中的少数几个key的数据量过大,而另一个RDD/Hive表中的所有key都分布比较均匀。
解决思路:将数据量过大的key数据拆分出来加上1-n随机前缀,将另一个表中对应的数据也拆分出来,并膨胀成n份,每份数据同样加上前缀,保证能够关联,这样再join就不会发生数据倾斜了。
Spark解决方案:
- 对包含少数几个数据量过大的key的那个RDD(大表),通过sample算子采样出一份样本来,然后统计一下每个key的数量,计算出来数据量最大的是哪几个key。
- 然后将这几个key对应的数据从原来的RDD中拆分出来,形成一个单独的RDD,并给每个key都打上n以内的随机数作为前缀,而不会导致倾斜的大部分key形成另外一个RDD。
- 接着将需要join的另一个RDD,也过滤出来那几个倾斜key对应的数据并形成一个单独的RDD,将每条数据膨胀成n条数据,这n条数据都按顺序附加一个0~n的前缀,不会导致倾斜的大部分key也形成另外一个RDD。
- 再将附加了随机前缀的独立RDD与另一个膨胀n倍的独立RDD进行join,此时就可以将原先相同的key打散成n份,分散到多个task中去进行join了。
- 而另外两个普通的RDD就照常join即可。 最后将两次join的结果使用union算子合并起来即可,就是最终的join结果。