【2021持续更新】大数据面试题整理-HDFS篇

导语

本专栏博文会整理日常工作与面试中最常用到的大数据相关组件与Java语言的架构、概念、知识点,方便大家进行查阅。
涉及到的面试题以及答案均为博主搜罗整理,并加上自己的理解编写而成。同时博主会在部分题目的下方添加管遇此题深入理解的博文连接,方便读者的深入理解。
希望大家可以通过此篇博文对于大数据相关概念有一个更深入的理解
还有哪些想看的面试题,读者可以在评论区补充,博主会在一天内进行更新!!!
最后预祝大家新的一年升职加薪,工资涨涨涨!

基础知识

HDFS读流程

在这里插入图片描述

1)跟NN通信查询元数据(block所在的DN的节点),找到文件块所在的DN的服务器。
2)挑选一台DN(就近原则,然后随机)服务器,请求建立socket流。
3)DN开始发送数据(从磁盘里读取数据放入流,一packet为单位做校验)
4)客户端以packet为单位接收,现在本地缓存,然后写入目标文件中,后面的block块就相当于append到前面的block块,最后合成最终需要的文件。

深入阅读:HDFS读写流程

HDFS写流程

在这里插入图片描述

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步)。

深入阅读:HDFS读写流程

HDFS文件副本放置策略

假设有一份数据,三副本

  • 第一个副本:在DataNode数据节点提交时,第一个块是本地节点,目的是节省了本地资源,占用了更少的带宽,如果是在集群外提交,则随机挑选一台磁盘不太慢,CPU不太忙的节点上;
  • 第二个副本:放置在与第一个副本不同的机架的节点上;
  • 第三个副本:与第二个副本相同机架的不同节点上;
  • 若有更多副本,随机放在节点中

HDFS的各进程名称与功能

  • NameNode:维护着文件的元数据,包括文件名、副本数、文件的 BlockId,以及 block 所在的服务器,会接受来自 Client 端的读写请求,和DataNode 的 Block 信息上报。
  • Secondary NameNode:用来监控HDFS状态的辅助后台程序。Secondary NameNode不同于NameNode,它不接受或者记录任何实时的数据变化,但是,它会与NameNode进行通信,以便定期地保存HDFS元数据快照。由于NameNode是单点的,通过Secondary NameNode的快照功能,可以将NameNode的宕机时间和数据损失降低到最小。同时,如果NameNode中的Fsimage到达了指定容量,则会和Secondary NameNode进行通信,进行checkoint操作。
  • DataNode:HDFS 的工作节点,他们根据客户端或者是 NameNode 的调度存储和检索数据,并且定期向 NameNode 发送他们所存储的块(block)的列表。
  • JournalNode:负责两个 NameNode 高可用时的数据同步保证数据一致,存放 NameNode 的 editlog 文件(元数据),部署在任意节点,奇数个。
  • JobTracker:JobTracker后台程序用来连接应用程序与Hadoop。用户代码提交到集群以后,由JobTracker决定哪个文件将被处理,并且为 不同的task分配节点。同时,它还监控所有的task,一旦某个task失败了,JobTracker就会自动重新开启这个task,在大多数情况下这 个task会被放在不用的节点上。每个Hadoop集群只有一个JobTracker,一般运行在集群的Master节点上。
  • TaskTracker:TaskTracker与负责存储数据的DataNode相结合,其处理结构上也遵循主/从架构。JobTracker位于主节点,统领 MapReduce工作;而TaskTrackers位于从节点,独立管理各自的task。每个TaskTracker负责独立执行具体的task,而 JobTracker负责分配task。

深入阅读:hadoop详细了解5个进程的作用

常用的hdfs命令

  1. -help:显示帮助信息
hdfs fs -help rm
  1. -ls:显示目录信息
hdfs fs -ls /
  1. -mkdir:在HDFS上创建目录
hdfs fs -mkdir -p /user/ysir
  1. -get:从HDFS中拷贝到本地,等同于copyToLocal
hdfs fs -get /aaa/a.txt
  1. -put:将本地文件上传到HDFS,等同于copyFromLocal
hdfs fs -put ~/a.txt /
  1. -cat:显示文件内容
hdfs fs -cat /user/ysir/a.txt
  1. -chmod、-chown:修改文件权限、所有者
hdfs fs -chmod 777 /a.txt
hdfs fs -chown hdfs:hdfs /a.txt
  1. -cp:在HDFS中拷贝文件
hdfs fs -cp /aaa/a.txt /bbb/
  1. -mv:在HDFS目录中移动文件
hdfs fs -mv /aaa/a.txt /bbb/ 
  1. -rm:删除文件夹或者文件
hdfs fs -rm /user/ysir/a.txt

MapReduce中Shuffle过程

shuffle是MapReduce的核心,是map和reduce的中间过程。
在这里插入图片描述

Map->keyby->sort->combine->partition->reduce

map阶段:从磁盘读入数据 --> map函数 --> combine结果(非必需的过程)–> 结果写回磁盘。

map阶段中,当输出数据达到一定的值(阈值)时,会从内存写到磁盘;若小于阈值,则会缓存起来,可以减小磁盘IO开销。所以,可以通过设置适当的阈值大小,来优化性能。

reduce阶段:从map的输出中读入数据 --> sort(根据key值) --> reduce函数–> 结果到HDFS。

reduce阶段中,会从map端拉数据过来,可能会跨节点,应该尽量减少这种网络开销,使数据“本地化”。

partition:将map的结果发送到相应的reduce。

这就对partition有两个要求:

1)负载均衡。尽量将工作分配给不同的reduce。

2)效率。分配速度要快。

combiner:相当于本地化的reduce。

特点:map端的输出作为其输入;其输出作为reduce的输入。这就要求combiner要保持输入和输出类型的一致性,也就不适用求平均数、权益这样的运算。

深入阅读:MapReduce:详解Shuffle过程

HDFS文件存储格式

hdfs 文件存储格式分为两大类 行存储和列存储

  • 行存储:将一整行存储在一起,是一种连续的存储方式,例如SequenceFile,MapFile,缺点是如果只需要行中的某一列也必须把整行都读入内存当中

  • 列存储:列存储会把文件切割成若干列,每一列存储在一起,是需要那一列读取那一列,不需要的不用读取,例如parquet ORCfile,RCfile,列存储不适合流式写入,写入失败当前文件无法恢复因此flume采用行存储,列存储由于每一列中的数据类型相同所以可以根据数据类型选择适合的编码和压缩格式

  1. textfile
    textfile为默认格式,存储方式为行式存储,在检索时磁盘开销大 数据解析开销大,而对压缩的text文件 hive无法进行合并和拆分。

  2. SequenceFile
    Hadoop提供的一个行存储结构,Hadoop适合处理大文件而不适合处理小文件,所以sequencefile是为小文件提供的一种容器,将小文件包装起来形成一个SequenceFile类, 它用一种<key,value>的形式序列化数据导文件中。

  3. RCFile
    存储方式为数据按行分块,每块按照列存储的行列混合模式,具有压缩快,列存取快的特点。
    在使用时,读记录尽量涉及到的block最少,这样读取需要的列只需要读取每个row group 的头部定义,具有明显速度优势。
    读取全量数据的操作 性能可能比sequencefile没有明显的优势。

  4. ORCfile
    是RCfile的升级版,将数据划分为默认大小为250MB的stripe(条带),每个stripe包含索引,数据和footer,ORCfile包换索引比RCfile更加高效

  5. Parquet
    parquet基于Google的dremel,擅长处理深度嵌套的数据(有点类似于嵌套多层的json格式),parquet会将嵌套结构整合为平面列存储,

深入阅读:HDFS中的常用压缩算法及区别

HDFS文件压缩算法

  1. Gzip压缩
    优点:压缩率比较高,压缩/解压速度也比较快,hadoop本身支持。
    缺点:不支持分片。
    应用场景:当每个文件压缩之后在1个block块大小内,可以考虑用gzip压缩格式。
  2. lzo压缩
    优点:压缩/解压速度也比较快,合理的压缩率,支持分片,是Hadoop中最流行的压缩格式,支持Hadoop native库。
    缺点:压缩率比gzip要低一些,Hadoop本身不支持,需要安装,如果支持分片需要建立索引,还需要指定inputformat改为lzo格式。
    应用场景:一个很大的文本文件,压缩之后还大于200M以上的可以考虑,而且单个文件越大,lzo优点越明显。
  3. snappy压缩
    优点:支持Hadoop native库,高速压缩速度和合理的压缩率。
    缺点:不支持分片,压缩率比gzip要低,Hadoop本身不支持,需要安装。
    应用场景:当MapReduce作业的map输出的数据比较大的时候,作为map到reduce的中间数据的压缩格式。
  4. bzip2压缩
    优点:支持分片,具有很高的压缩率,比gzip压缩率都高,Hadoop本身支持,但不支持native。
    缺点:压缩/解压速度慢,不支持Hadoop native库。
    应用场景:适合对速度要求不高,但需要较高的压缩率的时候,可以作为mapreduce作业的输出格式,输出之后的数据比较大,处理之后的数据需要压缩存档减少磁盘空间并且以后数据用得比较少的情况。

深入阅读:HDFS中的常用压缩算法及区别

故障排查与调优

HDFS中小文件过多导致的问题与如何优化

小文件过多导致的问题
小文件是指文件size小于HDFS上block大小的文件。这样的文件会给hadoop的扩展性和性能带来严重问题。

  • 首先,在HDFS中,任何block,文件或者目录在内存中均以对象的形式存储,每个对象约占150byte,如果有1000 0000个小文件,每个文件占用一个block,则namenode大约需要2G空间。如果存储1亿个文件,则namenode需要20G空间。这样namenode内存容量严重制约了集群的扩展。
  • 其次,访问大量小文件速度远远小于访问几个大文件。HDFS最初是为流式访问大文件开发的,如果访问大量小文件,需要不断的从一个datanode跳到另一个datanode,严重影响性能。
  • 最后,处理大量小文件速度远远小于处理同等大小的大文件的速度。每一个小文件要占用一个slot,而task启动将耗费大量时间甚至大部分时间都耗费在启动task和释放task上。

优化方案

  1. 使用HAR(Hadoop Archives)
    为了缓解大量小文件带给namenode内存的压力,Hadoop 0.18.0引入了Hadoop Archives(HAR files),其本质就是在HDFS之上构建一个分层文件系统。通过执行hadoop archive 命令就可以创建一个HAR文件。在命令行下,用户可使用一个以har://开头的URL就可以访问HAR文件中的小文件。使用HAR files可以减少HDFS中的文件数量。
    下图为HAR文件的文件结构,可以看出来访问一个指定的小文件需要访问两层索引文件才能获取小文件在HAR文件中的存储位置,因此,访问一个HAR文件的效率可能会比直接访问HDFS文件要低。对于一个mapreduce任务来说,如果使用HAR文件作为其输入,仍旧是其中每个小文件对应一个map task,效率低下。所以,HAR files最好是用于文件归档。
    在这里插入图片描述
  2. 使用sequencefile
    SequenceFile核心是以文件名为key,文件内容为value组织小文件。10000个100KB的小文件,可以编写程序将这些文件放到一个SequenceFile文件,然后就以数据流的方式处理这些文件,也可以使用MapReduce进行处理。一个SequenceFile是可分割的,所以MapReduce可将文件切分成块,每一块独立操作。不像HAR,SequenceFile支持压缩。在大多数情况下,以block为单位进行压缩是最好的选择,因为一个block包含多条记录,压缩作用在block之上,比reduce压缩方式(一条一条记录进行压缩)的压缩比高。
    把已有的数据转存为SequenceFile比较慢。比起先写小文件,再将小文件写入SequenceFile,一个更好的选择是直接将数据写入一个SequenceFile文件,省去小文件作为中间媒介。
  3. MapReduce过程中使用CombineFileInputFormat
    CombineFileInputFormat是一种新的inputformat,用于将多个文件合并成一个单独的split,另外,它会考虑数据的存储位置。

MapReduce跑得慢的原因

Mapreduce 程序效率的瓶颈在于两点:

  1. 计算机性能

    CPU、内存、磁盘健康、网络

  2. I/O 操作优化

    (1)数据倾斜

    (2)map和reduce数设置不合理

    (3)reduce等待过久

    (4)小文件过多

    (5)大量的不可分块的超大文件

    (6)spill次数过多

    (7)merge次数过多等。

深入阅读:Hadoop(三)mapreduce 跑的慢的原因及其优化方法

MapReduce优化方法

  1. 数据输入

    (1)合并小文件:在执行mr任务前将小文件进行合并,大量的小文件会产生大量的map任务,增大map任务装载次数,而任务的装载比较耗时,从而导致 mr 运行较慢。

    (2)采用ConbinFileInputFormat来作为输入,解决输入端大量小文件场景。

  2. map阶段

    (1)减少spill次数:通过调整io.sort.mb及sort.spill.percent参数值,增大触发spill的内存上限,减少spill次数,从而减少磁盘 IO。

    (2)减少merge次数:通过调整io.sort.factor参数,增大merge的文件数目,减少merge的次数,从而缩短mr处理时间。

    (3)在 map 之后先进行combine处理,减少 I/O。

  3. reduce阶段

    (1)合理设置map和reduce数:两个都不能设置太少,也不能设置太多。太少,会导致task等待,延长处理时间;太多,会导致 map、reduce任务间竞争资源,造成处理超时等错误。

    (2)设置map、reduce共存:调整slowstart.completedmaps参数,使map运行到一定程度后,reduce也开始运行,减少reduce的等待时间。

    (3)规避使用reduce,因为Reduce在用于连接数据集的时候将会产生大量的网络消耗。

    (4)合理设置reduce端的buffer,默认情况下,数据达到一个阈值的时候,buffer中的数据就会写入磁盘,然后reduce会从磁盘中获得所有的数据。也就是说,buffer和reduce是没有直接关联的,中间多个一个写磁盘->读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得buffer中的一部分数据可以直接输送到reduce,从而减少IO开销:mapred.job.reduce.input.buffer.percent,默认为0.0。当值大于0的时候,会保留指定比例的内存读buffer中的数据直接拿给reduce使用。这样一来,设置buffer需要内存,读取数据需要内存,reduce计算也要内存,所以要根据作业的运行情况进行调整。

  4. IO传输

    (1)采用数据压缩的方式,减少网络IO的的时间。安装Snappy和LZOP压缩编码器。

    (2)使用SequenceFile二进制文件

MapReduce数据倾斜描述与解决方案

描述:
简单来说数据倾斜就是Map阶段数据的key分化严重不均,在进行shuffle之后,一部分reduce节点数据过多,一部分节点数据过少,最终导致整个程序运行时间很长才结束。

一般会有两种情况:

  • 一种是唯一值非常少,极少数值有非常多的记录值(唯一值少于几千)
  • 一种是唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一

举个 word count 的入门例子,它的map 阶段就是形成 (“aaa”,1)的形式,然后在reduce 阶段进行 value 相加,得出 “aaa” 出现的次数。若进行 word count 的文本有100G,其中 80G 全部是 “aaa” 剩下 20G 是其余单词,那就会形成 80G 的数据量交给一个 reduce 进行相加,其余 20G 根据 key 不同分散到不同 reduce 进行相加的情况。如此就造成了数据倾斜,最后就是很多reduce节点跑到 99%然后一直在原地等着那80G的reduce节点跑完。

解决方案:

  1. 增加reduce 的jvm内存
    既然reduce 本身的计算需要以合适的内存作为支持,在硬件环境容许的情况下,增加reduce 的内存大小显然有改善数据倾斜的可能,这种方式尤其适合数据分布第一种情况,单个值有大量记录, 这种值的所有纪录已经超过了分配给reduce 的内存,无论你怎么样分区这种情况都不会改变. 当然这种情况的限制也非常明显, 1.内存的限制存在,2.可能会对集群其他任务的运行产生不稳定的影响.
  2. 增加reduce 个数
    这个对于数据分布第二种情况有效,唯一值较多,单个唯一值的记录数不会超过分配给reduce 的内存. 如果发生了偶尔的数据倾斜情况,增加reduce 个数可以缓解偶然情况下的某些reduce 不小心分配了多个较多记录数的情况. 但是对于第一种数据分布无效.
  3. 自己实现partition类
    自定义partition类,将指定key的数据分配至指定的reduce中,这种方法需要对数据有一个明确的了解,知道数据中key的分布情况。
  4. 添加combiner操作
    combiner相当于提前进行reduce,就会把一个mapper中的相同key进行了聚合,减少shuffle过程中数据量,以及reduce端的计算量。这种方法可以有效的缓解数据倾斜问题,但是如果导致数据倾斜的key 大量分布在不同的mapper的时候,这种方法就不是很有效了。

深入阅读:Hadoop数据倾斜及解决办法

HDFS调优技巧

深入阅读:HDFS集群优化篇

猜你喜欢

转载自blog.csdn.net/mrliqifeng/article/details/113195262