Hadoop面试题(秋招持续更新)

Hadoop面试题(待更新)

HDFS部分:

1.HDFS读文件流程
在这里插入图片描述
1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。并返回元数据。
2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
4)客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。
写文件流程
在这里插入图片描述
1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
2)NameNode返回是否可以上传。
3)客户端请求第一个 Block上传到哪几个DataNode服务器上。
4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
6)dn1、dn2、dn3逐级应答客户端。
7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
8)当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)。
2.如果在写入过程中,Datanode宕机了,会怎么处理?
如果写入时,一个datanode挂掉,会将已经写入的数据放置到queue的顶部,并将挂掉的datanode移出pipline,讲数据写入到剩余的datanode.在写入结束后, namenode会收集datanode的信息,发现此文件的副本数没有达到配置的要求(default=3),然后寻找一个datanode保存副本。
3.hadoop高可用底层实现
hadoop高可用的实现依赖于zk,在高可用的环境下,会有ZKFC(ZKFailoverController)这个进程(是hadoop的进程),进程启动后,会初始化HealthMonitor和ActiveStandbyElector服务,其中HealthMonitor会监控NameNode健康状况。ActiveStandbyElector服务进行主备选举。主备的选举主要是依据谁可以在zk上创建临时节点(ActiveStandbyElectorLock),而由于ZK的写一致性,只可以保证一个被创建,所有ActiveStandbyElector都会在Zookeeper注册一个Watcher来监听这个临时节点的状态变化,如果active NameNode对应的HealthMonitor检测到NameNode状态异常时,会删除在Zookeeper上创建的临时节点ActiveStandbyElectorLock。然后standby NameNode的ActiveStandbyElector注册的Watcher就会收到这个节点的NodeDeleted事件,并会再次创建ActiveStandbyElectorLock,如果成功,则standby NameNode将被选举为active。
注:一个为永久节点(ActiveBreadCrumb),永久节点是为了防止active状态的NameNode非正常退出后再恢复导致的双主脑裂问题
4.hdfs默认副本数为什么是3?
hdfs采用机架感知策略来改进数据可靠性,可用性和网络带宽的利用率
在大多数情况下,hdfs的副本数是3,hdfs的存放策略是一个副本在本地机架节点上,另外一个副本存放在同一机架的另一个节点上,第三个副本存放在不同机架的节点上
这种策略是减少了机架间的数据传输,提高了写操作的效率。
5.HDFS小文件问题,如何解决?
弊端:(1)增加map开销,一个小文件就是一个map任务
(2)造成namenode内存浪费
解决办法:
(1)可以将小文件合成顺序文件:将文件名作为键,文件内容为值
(2)可以使用CombineFileputFormat将多个小文件打包到一个切片
(3)自带的archive工具,减少namenode的负载
6.namenode如何管理元数据
存储于内存里,主要元数据就是文件的路径名,block位置,类似java对象的方式,挂了重启后,加载fsimage,辅助通过editLog恢复。fsimage是元数据镜像备份,还有个editLog是操作日志

MR

1.mr流程:
在这里插入图片描述
在这里插入图片描述

客服端提交的时候,将数据进行切片处理,
由InputSplit来读取外部数据,调用RecordReader的read()方法来读取,返回K-V对,输入到map,会运行我们实现的Mapper的处理逻辑,对数据进行映射操作。 (多少个切片多少个map)
context.write的方法被调用,outputCollector组件会将结果写入到环形缓冲区(buffer默认大小为100M,可以通过io.sort.mb配置),并且获得分区(默认哈希分区),
当环形缓冲区到达80%,spiller组件进行溢写,会按照定义的分区(默认hashpartition(也可以自定义分区)),并且按照key排序(快排)。 (多次溢写会形成多个文件)
进行归并排序,将同一分区不同的溢写文件进行归并排序,形成大的文件,且区内有序。(多少分区多少reduce)
reduce阶段,每个reduce任务开始从多个map上拷贝属于自己partition(map阶段已经做好partition,而且每个reduce任务通过GroupingComparator()分辨同一分区数据;拷贝过程是在不同节点之间,Reducer上拷贝线程基于HTTP来通过网络传输数据)。
每个reduce任务拷贝的map任务结果的指定partition,也是先将数据放入到自带的一个buffer中(buffer默认大小为Heap内存的70%,可以通过mapred.job.shuffle.input.buffer.percent配置),如果配置了map结果进行压缩,则这时要先将数据解压缩后放入buffer中。
reduce自带的buffer使用容量达到一定门限(默认0.66或66%,可以通过mapred.job.shuffle.merge.percent配置),或者buffer中存放的map的输出的数量达到一定门限(默认1000,可以通过mapred.inmem.merge.threshold配置),buffer中的数据将会被写入到磁盘中。
在将buffer中多个map输出合并写入磁盘之前,如果设置了Combiner,则会化简压缩合并的map输出。
当属于该reducer的map输出全部拷贝完成,则会在reducer上生成多个文件,这时开始执行合并操作,并保持每个map输出数据中Key的有序性,将多个文件合并成一个文件(在reduce端可能存在buffer和磁盘上都有数据的情况,这样在buffer中的数据可以减少一定量的I/O写入操作开销)。
最后,执行reduce阶段,运行我们实现的Reducer中化简逻辑,最终将结果直接输出到HDFS中(因为Reducer运行在DataNode上,输出结果的第一个replica直接在存储在本地节点上)。

2.map-reduce编程模型
首先map task会从本地文件系统读取数据,转换成key-value形式的键值对集合
使用的是hadoop内置的数据类型,比如longwritable、text等
将键值对集合输入mapper进行业务处理过程,将其转换成需要的key-value在输出
之后会进行一个partition分区操作,默认使用的是hashpartitioner,可以通过重写hashpartitioner的getpartition方法来自定义分区规则
之后会对key进行进行sort排序,grouping分组操作将相同key的value合并分组输出,在这里可以使用自定义的数据类型,重写WritableComparator的Comparator方法来自定义排序规则,重写RawComparator的compara方法来自定义分组规则
之后进行一个combiner归约操作,其实就是一个本地段的reduce预处理,以减小后面shuffle和reducer的工作量
reduce task会通过网络将各个数据收集进行reduce处理,最后将数据保存或者显示,结束整个job

3.shuffle过程:
在这里插入图片描述

1)Map 方法之后 Reduce 方法之前这段处理过程叫 Shuffle
2)Map 方法之后,数据首先进入到分区方法,把数据标记好分区,然后把数据发送到环形缓冲区;环形缓冲区默认大小 100m,环形缓冲区达到 80%时,进行溢写;溢写前对数据进行排序,排序按照对 key 的索引进行字典顺序排序,排序的手段快排;溢写产生大量溢写文件,需要对溢写文件进行归并排序;对溢写的文件也可以进行 Combiner 操作,前提是汇总操作,求平均值不行。最后将文件按照分区存储到磁盘,等待 Reduce 端拉取。
3)每个 Reduce拉取 Map 端对应分区的数据。拉取数据后先存储到内存中,内存不够了,再存储到磁盘。拉取完所有数据后,采用归并排序将内存和磁盘中的数据都进行排序。在进入 Reduce方法前,可以对数据进行分组操作。

3.mr的切片机制
默认是128M
需要去把maxSize与blockSize中的小值去与minSize比,取大的那个,而minSize在是在默认值1字节和自己设置的值取最大的。maxSize的值与取最小值同理,如果没有设置,取long整型类型的最大值

protected long computeSplitSize(long blockSize, long minSize, long maxSize) {
    return Math.max(minSize, Math.min(maxSize, blockSize));
}

4.缓冲区的作用?环形缓冲区如何调整?是否可以无限大?
使用环形缓冲区,便于写入缓冲区和写出缓冲区同时进行。总大小在配置文件中io.sort.mb属性设置。不可以无限大,会导致系统资源崩溃,可以设置为切片大小(128m)
5.reduce函数如何知道从那台机器获取map输出?
map任务成功完成之后,它们通知其父tasktracker状态已更新,然后tasktracker通知jobtracker。这些通知都是通过心跳机制传输的。因此,对于指定作业,jobtracker知道map输出和tasktracker之间的映射关系。reduce中的一个线程定期询问jobtracker以便获得map输出的位置,再通过GroupingComparator()分辨同一分区数据,直到它获得所有输出位置。由于reducer可能失败,因此tasktracker并没有在第一个reducer检索到map输出时就立即从磁盘上删除它们。相反,tasktracker会等待,直到jobtracker告知它可以删除map输出,这是作业完成后执行的。
6.shuffle,为什么Map端输出的时候需要排序?
MR在reduce阶段需要分组,将key相同的放在一起进行规约,为了达到该目的,有两种算法:hashmap和sort,前者太耗内存,而排序通过外排可对任意数据量分组,只要磁盘够大就行。map端排序是为了减轻reduce端排序的压力。
7.mr实现全排序
1.设置一个reduce进行排序,效率低
2.自定义分区,每个分区有序,且分区内有序,从而全局有序。比如key代表的是一个年龄。我们可以把数据输出到10个reduer。1-10岁之间发往第0个reduce,11-20发往第2个reduce,会造成数据倾斜(有些分区数据可能会大)
3,、使用TotalOrderPartition
8.map join和reduce join
map join原理:首先在本地生成一个local task读取比较小的表dept(默认25MB),然后将表写入Hash Table Files ,上传到HDFS的缓存中,该缓存会将这些文件发送到每个Mapper的本地磁盘上,然后启动一个map作业,每读取一条数据,就与缓存中的小表进行join操作,直至整个大表读取结束。
在这里插入图片描述
reduce join:通过将关联的条件作为map输出的key,将两表满足join条件的数据并携带数据所来源的文件信息,发往同一个reduce task,在reduce中进行数据的串联
在这里插入图片描述
在这里插入图片描述

yarn

1.yarn的基本架构
在这里插入图片描述
2.工作流程
在这里插入图片描述
(1)MR程序提交到客户端所在的节点。
(2)YarnRunner向ResourceManager申请一个Application。
(3)RM将该应用程序的资源路径返回给YarnRunner。
(4)该程序将运行所需资源提交到HDFS上。
(5)程序资源提交完毕后,申请运行mrAppMaster。
(6)RM将用户的请求初始化成一个Task。
(7)其中一个NodeManager领取到Task任务。
(8)该NodeManager创建容器Container,并产生MRAppmaster。
(9)Container从HDFS上拷贝资源到本地。
(10)MRAppmaster向RM 申请运行MapTask资源。
(11)RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器。
(12)MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动MapTask,MapTask对数据分区排序。
(13)MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask。
(14)ReduceTask向MapTask获取相应分区的数据。
(15)程序运行完毕后,MR会向RM申请注销自己。

作业提交全过程详解
(1)作业提交
第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。
第2步:Client向RM申请一个作业id。
第3步:RM给Client返回该job资源的提交路径和作业id。
第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。
第5步:Client提交完资源后,向RM申请运行MrAppMaster。
(2)作业初始化
第6步:当RM收到Client的请求后,将该job添加到容量调度器中。
第7步:某一个空闲的NM领取到该Job。
第8步:该NM创建Container,并产生MRAppmaster。
第9步:下载Client提交的资源到本地。
(3)任务分配
第10步:MrAppMaster向RM申请运行多个MapTask任务资源。
第11步:RM将运行MapTask任务分配给另外两个NodeManager,另两个NodeManager分别领取任务并创建容器。
(4)任务运行
第12步:MR向两个接收到任务的NodeManager发送程序启动脚本,这两个NodeManager分别启动MapTask,MapTask对数据分区排序。
第13步:MrAppMaster等待所有MapTask运行完毕后,向RM申请容器,运行ReduceTask。
第14步:ReduceTask向MapTask获取相应分区的数据。
第15步:程序运行完毕后,MR会向RM申请注销自己。
(5)进度和状态更新
YARN中的任务将其进度和状态(包括counter)返回给应用管理器, 客户端每秒(通过mapreduce.client.progressmonitor.pollinterval设置)向应用管理器请求进度更新, 展示给用户。
(6)作业完成
除了向应用管理器请求作业进度外, 客户端每5秒都会通过调用waitForCompletion()来检查作业是否完成。时间间隔可以通过mapreduce.client.completion.pollinterval来设置。作业完成之后, 应用管理器和Container会清理工作状态。作业的信息会被作业历史服务器存储以备之后用户核查。

3.yarn调度器

1)Hadoop 调度器重要分为三类:
FIFO 、Capacity Scheduler(容量调度器)和 Fair Sceduler(公平调度器)。(用后面2个)
Hadoop2.7.2 默认的资源调度器是 容量调度器
2)区别:
FIFO 调度器:先进先出,同一时间队列中只有一个任务在执行。
在这里插入图片描述
容量调度器:多队列;每个队列内部先进先出,同一时间队列中只有一个任务在执行。队列的并行度为队列的个数。
在这里插入图片描述
公平调度器:多队列;每个队列内部按照缺额大小分配资源启动任务,同一时间队列中有多个任务执行。队列的并行度大于等于队列的个数。 会出现饿死
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值