4 Hadoop 面试真题
- 1. Apache Hadoop 3.0.0
- 2. HDFS 3.x 数据存储新特性-纠删码
- Hadoop面试真题
1. Apache Hadoop 3.0.0
Apache Hadoop 3.0.0在以前的主要发行版本(hadoop-2.x)上进行了许多重大改进。
- 最低要求的Java版本从Java 7增加到Java 8
现在,已针对Java 8的运行时版本编译了所有Hadoop JAR。仍在使用Java 7或更低版本的用户必须升级到Java 8。 - 支持HDFS中的纠删码
纠删码是一种持久存储数据的方法,可节省大量空间。与标准HDFS副本机制的3倍开销相比,像Reed-Solomon(10,4) 这样的标准编码的空间开销是1.4倍。
由于纠删码在重建期间会带来额外的开销,并且大多数情况下会执行远程读取,因此传统上已将其用于存储较冷,访问频率较低的数据。
在部署此功能时应考虑纠删码机制的网络和CPU开销。
关于HDFS中纠删码更详细的介绍,可查看我之前写的这篇文章: 深入剖析 HDFS 3.x 新特性-纠删码 - Shell脚本重写
Hadoop Shell脚本已被重写,以修复许多长期存在的错误并包括一些新功能。Hadoop的开发人员尽管一直在寻求兼容性,但是某些更改可能会破坏现有的安装。 - MapReduce 任务本地优化
MapReduce 增加了对 map output 收集器的本地执行的支持,对于 shuffle 密集型工作,这可以使性能提高30%或更多。 - 支持两个以上的 NameNode
在之前的版本中,HDFS的高可用最多支持两个NameNode。在HDFS 3.x 版本中,通过将编辑复制到法定数量的三个JournalNode,该体系结构能够容忍系统中任何一个节点的故障。
但是,某些部署需要更高的容错度。这个新特性启用了这一点,该功能允许用户运行多个备用NameNode。例如,通过配置三个NameNode和五个JournalNode,群集可以忍受两个节点的故障,而不仅仅是一个节点的故障。 - 多个服务的默认端口已更改
以前,多个Hadoop服务的默认端口在Linux临时端口范围内(32768-61000)。这意味着在启动时,服务有时会由于与另一个应用程序的冲突而无法绑定到端口。
这些冲突的端口已移出临时范围,具体的端口更改如下:
NameNode 的端口: 50070 --> 9870, 8020 --> 9820, 50470 --> 9871;
Secondary NameNode 的端口: 50091 --> 9869, 50090 --> 9868;
DataNode 的端口: 50020 --> 9867, 50010 --> 9866, 50475 --> 9865, 50075 --> 9864;
Hadoop KMS 的端口: 16000 --> 9600(HBase的HMaster端口号与Hadoop KMS端口号冲突。两者都使用16000,因此 Hadoop KMS 更改为9600)。 - 支持Microsoft Azure数据湖和阿里云对象存储系统文件系统连接器
Hadoop现在支持与Microsoft Azure数据湖和Aliyun对象存储系统集成,作为与Hadoop兼容的替代文件系统。 - 数据内节点平衡器
单个DataNode可管理多个磁盘。在正常的写操作过程中,磁盘将被均匀填充。但是,添加或替换磁盘可能会导致DataNode内部出现严重偏差。原有的HDFS平衡器无法处理这种情况。新版本的HDFS中有平衡功能处理,该功能通过hdfs diskbalancer CLI调用。 - 基于HDFS路由器的联合
基于HDFS路由器的联合添加了一个RPC路由层,该层提供了多个HDFS名称空间的联合视图。这简化了现有HDFS客户端对联合群集的访问。 - YARN资源类型
YARN资源模型已被通用化,以支持用户定义的CPU和内存以外的可计数资源类型。例如,集群管理员可以定义资源,例如GPU,软件许可证或本地连接的存储。然后可以根据这些资源的可用性来调度YARN任务。
2. HDFS 3.x 数据存储新特性-纠删码
HDFS是一个高吞吐、高容错的分布式文件系统,但是HDFS在保证高容错的同时也带来了高昂的存储成本,比如有5T的数据存储在HDFS上,按照HDFS的默认3副本机制,将会占用15T的存储空间。那么有没有一种能达到和副本机制相同的容错能力但是能大幅度降低存储成本的机制呢,有,就是在HDFS 3.x 版本引入的纠删码机制。
-
EC介绍
Erasure Coding 简称 EC,中文名:纠删码
EC(纠删码)是一种编码技术,在 HDFS 之前,这种编码技术在廉价磁盘冗余阵列(RAID)中应用最广泛,RAID 通过条带化技术实现 EC,条带化技术就是一种自动将 I/O 的负载均衡到多个物理磁盘上的技术,原理就是将一块连续的数据分成很多小部分并把他们分别存储到不同磁盘上去,这就能使多个进程同时访问数据的多个不同部分而不会造成磁盘冲突(当多个进程同时访问一个磁盘时,可能会出现磁盘冲突),而且在需要对这种数据进行顺序访问的时候可以获得最大程度上的 I/O 并行能力,从而获得非常好的性能。
在HDFS中,把连续的数据分成很多的小部分称为条带化单元,对于原始数据单元的每个条带单元,都会计算并存储一定数量的奇偶检验单元,计算的过程称为编码,可以通过基于剩余数据和奇偶校验单元的解码计算来恢复任何条带化单元上的错误。 -
HDFS数据冗余存储策略
HDFS的存储策略是副本机制,这种存储方式使得数据存储的安全性得到提高,但同时也带来了额外的开销,HDFS默认的3副本方案在存储空间和其他资源(如网络带宽)上有200%的额外开销,但是对于I/O活动相对较低的数据,在正常期间很少访问其他块副本,但是仍然消耗与第一个副本相同的资源量。
因此,HDFS 3.x 版本一个重大改进就是使用纠删码(EC)代替副本机制,纠删码技术提供了与副本机制相同的容错能力,而存储空间却少得多。在典型的纠删码(EC)设置中,存储开销不超过50%。 -
EC算法实现原理
EC的实现算法有很多种,较为常见的一种算法是Reed-Solomon(RS),它有两个参数,记为RS(k,m),k 表示数据块,m 表示校验块,有多少个校验块就最多可容忍多少个块(包括数据块和校验块)丢失,具体原理通过如下例子解释:
我们使用RS(3,2),表示使用 3 个原始数据块,2 个校验块。
例:由RS(3,2) 可求出它的生成矩阵 GT,和 7、8、9 三个原始数据块 Data,通过矩阵乘法,计算出来两个校验数据块 50、122。这时原始数据加上校验数据,一共五个数据块:7、8、9、50、122,可以任意丢两个,然后通过算法进行恢复,矩阵乘法如下图所示:
矩阵乘法
GT 是生成矩阵,RS(k,m) 的生成矩阵就是 m 行 k 列的矩阵;
Data 代表原始数据,7,8,9代表原始数据块;
Parity 代表校验数据,50,122代表校验数据块。
所以3个原始数据块,如果使用2个校验块,EC编码总共占用5个数据块的磁盘空间,与2副本机制占用6个数据块的磁盘空间容错能力相当。
-
EC的应用场景
将EC技术集成进HDFS可以提高存储效率,同时仍提供与传统的基于副本的HDFS部署类似的数据持久性。例如,一个具有6个块的3副本文件将消耗 6 * 3 = 18 个磁盘空间。但是,使用EC(6个数据,3个校验)部署时,它将仅消耗9个磁盘空间块。
但是EC在编码过程及数据重建期间会大量的使用CPU资源,并且数据大部分是执行远程读取,所以还会有大量的网络开销。
所以,对于CPU资源紧张且存储成本较低的情况下,可以采用副本机制存储数据,对于CPU资源有剩余且存储成本较高的情况下,可以采用EC机制存储数据。 -
EC在HDFS的架构
HDFS 是直接使用 Online EC(以EC格式写入数据),避免了转换阶段并节省了存储空间。Online EC 还通过并行利用多个磁盘主轴来增强顺序I/O性能。在具有高端网络的群集中,这尤其理想。其次,它自然地将一个小文件分发到多个DataNode,而无需将多个文件捆绑到一个编码组中。这极大地简化了文件操作,例如删除,磁盘配额以及namespaces之间的迁移。
在一般HDFS集群中,小文件可占总存储消耗的3/4以上,为了更好的支持小文件,HDFS目前支持条形布局(Striping Layout)的EC方案,而HDFS连续布局(Contiguous Layout)方案正在开发中。
1.条形布局:
条形布局
优点:
客户端缓存数据较少;
无论文件大小都适用。
缺点:
会影响一些位置敏感任务的性能,因为原先在一个节点上的块被分散到了多个不同的节点上;
和多副本存储策略转换比较麻烦。
2.连续布局:
连续布局
优点:
容易实现;
方便和多副本存储策略进行转换。
缺点:
需要客户端缓存足够的数据块;
不适合存储小文件。
传统模式下 HDFS 中文件的基本构成单位是block,而EC模式下文件的基本构成单位是block group。以RS(3,2)为例,每个block group包含3个数据块,2个校验块。
HDFS对于引入EC模式所做的主要扩展如下:
NameNode:HDFS文件在逻辑上由block group组成,每个block group包含一定数量的内部块,为了减少这些内部块对NameNode内存消耗,HDFS引入了新的分层块命名协议。可以从其任何内部块的ID推断出block group的ID。这允许在块组而不是块的级别进行管理。
Client:客户端读取和写入路径得到了增强,可以并行处理block group中的多个内部块。
DataNode:DataNode运行额外ErasureCodingWorker(ECWorker)任务,用于对失败的纠删编码块进行后台恢复。NameNode检测到失败的EC块, 会选择一个DataNode进行恢复工作。此过程类似于失败时如何重新恢复副本的块。重建执行三个关键的任务节点:
1.从源节点读取数据:使用专用线程池从源节点并行读取输入数据。基于EC策略,对所有源目标的发起读取请求,并仅读取最少数量的输入块进行重建。
2.解码数据并生成输出数据:从输入数据解码新数据和奇偶校验块。所有丢失的数据和奇偶校验块一起解码。
3.将生成的数据块传输到目标节点:解码完成后,恢复的块将传输到目标DataNodes。
纠删码策略:为了适应异构的工作负载,HDFS群集中的文件和目录允许具有不同的复制和纠删码策略。纠删码策略封装了如何对文件进行编码/解码。每个策略由以下信息定义:
1.EC模式:这包括EC组(例如6 + 3)中的数据和奇偶校验块的数量,以及编解码器算法(例如Reed-Solomon,XOR)。
2.条带化单元的大小。这确定了条带读取和写入的粒度,包括缓冲区大小和编码工作。
我们可以通过XML文件定义自己的EC策略,该文件必须包含以下三个部分:
1.layoutversion:这表示EC策略XML文件格式的版本。
2.schemas:这包括所有用户定义的EC模式。
3.policies:这包括所有用户定义的EC策略,每个策略均由schema id和条带化单元的大小(cellsize)组成。
Hadoop conf目录中有一个配置EC策略的XML示例文件,配置时可以参考该文件,文件名称为user_ec_policies.xml.template。
-
集群的硬件配置
纠删码对群集在CPU和网络方面有一定的要求:
1.编码和解码工作会消耗HDFS客户端和DataNode上的额外CPU。
2.纠删码文件也分布在整个机架上,以实现机架容错。这意味着在读写条带化文件时,大多数操作都是在机架上进行的。因此,网络二等分带宽非常重要。
3.对于机架容错,拥有至少与配置的EC条带宽度一样多的机架也很重要。对于EC策略RS(6,3),这意味着最少要有9个机架,理想情况下是10或11个机架,以处理计划内和计划外的中断。对于机架少于条带宽度的群集,HDFS无法保持机架容错,但仍会尝试在多个节点之间分布条带化文件以保留节点级容错。 -
最后
在HDFS默认情况下,所有的EC策略是被禁止的,我们可以根据群集的大小和所需的容错属性,通过hdfs ec [-enablePolicy -policy]命令启用EC策略。
例如,对于具有9个机架的群集,像RS-10-4-1024k这样的策略将不会保留机架级的容错能力,而RS-6-3-1024k或RS-3-2-1024k可能更合适。
RS-10-4-1024k 表示有10个数据块,4个校验块。
在副本机制下,我们可以设置副本因子,指定副本的数量,但是在EC策略下,指定副本因子是没有意义的,因为它始终为1,无法通过相关命令进行更改。
Hadoop面试真题
hadoop中常问的就三块,第一:分布式存储(HDFS);第二:分布式计算框架(MapReduce);第三:资源调度框架(YARN)。
1. 请说下HDFS读写流程
这个问题虽然见过无数次,面试官问过无数次,还是有不少面试者不能完整的说出来,所以请务必记住。并且很多问题都是从HDFS读写流程中引申出来的。
HDFS写流程:
1.Client客户端发送上传请求,通过RPC与NameNode建立通信,NameNode检查该用户是否有上传权限,以及上传的文件是否在HDFS对应的目录下重名,如果这两者有任意一个不满足,则直接报错,如果两者都满足,则返回给客户端一个可以上传的信息;
2.Client根据文件的大小进行切分,默认128M一块,切分完成之后给NameNode发送请求第一个block块上传到哪些服务器上;
3.NameNode收到请求之后,根据网络拓扑和机架感知以及副本机制进行文件分配,返回可用的DataNode的地址;
注:Hadoop在设计时考虑到数据的安全与高效, 数据文件默认在HDFS上存放三份, 存储策略为本地一份,同机架内其它某一节点上一份, 不同机架的某一节点上一份。
4.客户端收到地址之后与服务器地址列表中的一个节点如A进行通信,本质上就是RPC调用,建立pipeline,A收到请求后会继续调用B,B在调用C,将整个pipeline建立完成,逐级返回Client;
5.Client开始向A上发送第一个block(先从磁盘读取数据然后放到本地内存缓存),以packet(数据包,64kb)为单位,A收到一个packet就会发送给B,然后B发送给C,A每传完一个packet就会放入一个应答队列等待应答;
6.数据被分割成一个个的packet数据包在pipeline上依次传输,在pipeline反向传输中,逐个发送ack(命令正确应答),最终由pipeline中第一个DataNode节点A将pipelineack发送给Client;
7.当一个block传输完成之后, Client再次请求NameNode上传第二个block,NameNode重新选择三台DataNode给Client。
HDFS读流程:
1.Client向NameNode发送RPC请求。请求文件block的位置;
2.NameNode收到请求之后会检查用户权限以及是否有这个文件,如果都符合,则会视情况返回部分或全部的block列表,对于每个block,NameNode都会返回含有该block副本的DataNode地址;这些返回的DataNode地址,会按照集群拓扑结构得出DataNode与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离 Client 近的排靠前;心跳机制中超时汇报的DataNode状态为STALE,这样的排靠后;
3.Client选取排序靠前的DataNode来读取block,如果客户端本身就是DataNode,那么将从本地直接获取数据(短路读取特性);
4.底层上本质是建立Socket Stream(FSDataInputStream),重复的调用父类DataInputStream的read方法,直到这个块上的数据读取完毕;
5.当读完列表的block后,若文件读取还没有结束,客户端会继续向NameNode 获取下一批的block列表;
6.读取完一个block都会进行checksum验证,如果读取DataNode时出现错误,客户端会通知NameNode,然后再从下一个拥有该block副本的DataNode 继续读;
7.read方法是并行的读取block信息,不是一块一块的读取;NameNode只是返回Client请求包含块的DataNode地址,并不是返回请求块的数据;
8.最终读取来所有的block会合并成一个完整的最终文件;
2. HDFS在读取文件的时候,如果其中一个块突然损坏了怎么办
客户端读取完DataNode上的块之后会进行checksum验证,也就是把客户端读取到本地的块与HDFS上的原始块进行校验,如果发现校验结果不一致,客户端会通知NameNode,然后再从下一个拥有该block副本的DataNode继续读。
3. HDFS在上传文件的时候,如果其中一个DataNode突然挂掉了怎么办
客户端上传文件时与DataNode建立pipeline管道,管道的正方向是客户端向DataNode发送的数据包,管道反向是DataNode向客户端发送ack确认,也就是正确接收到数据包之后发送一个已确认接收到的应答。
当DataNode突然挂掉了,客户端接收不到这个DataNode发送的ack确认,客户端会通知NameNode,NameNode检查该块的副本与规定的不符,NameNode会通知DataNode去复制副本,并将挂掉的DataNode作下线处理,不再让它参与文件上传与下载。
4. NameNode在启动的时候会做哪些操作
NameNode数据存储在内存和本地磁盘,本地磁盘数据存储在fsimage镜像文件和edits编辑日志文件。
首次启动NameNode:
1.格式化文件系统,为了生成fsimage镜像文件;
2.启动NameNode:
读取fsimage文件,将文件内容加载进内存
等待DataNade注册与发送block report
3.启动DataNode:
向NameNode注册
发送block report
检查fsimage中记录的块的数量和block report中的块的总数是否相同
4.对文件系统进行操作(创建目录,上传文件,删除文件等):
此时内存中已经有文件系统改变的信息,但是磁盘中没有文件系统改变的信息,此时会将这些改变信息写入edits文件中,edits文件中存储的是文件系统元数据改变的信息。
第二次启动NameNode:
1.读取fsimage和edits文件;
2.将fsimage和edits文件合并成新的fsimage文件;
3.创建新的edits文件,内容开始为空;
4.启动DataNode。
5. Secondary NameNode了解吗,它的工作机制是怎样的
Secondary NameNode是合并NameNode的edit logs到fsimage文件中;
它的具体工作机制:
1.Secondary NameNode询问NameNode是否需要checkpoint。直接带回NameNode是否检查结果;
2.Secondary NameNode请求执行checkpoint;
3.NameNode滚动正在写的edits日志;
4.将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode;
5.Secondary NameNode加载编辑日志和镜像文件到内存,并合并;
6.生成新的镜像文件fsimage.chkpoint;
7.拷贝fsimage.chkpoint到NameNode;
8.NameNode将fsimage.chkpoint重新命名成fsimage;
所以如果NameNode中的元数据丢失,是可以从Secondary NameNode恢复一部分元数据信息的,但不是全部,因为NameNode正在写的edits日志还没有拷贝到Secondary NameNode,这部分恢复不了。
6. Secondary NameNode不能恢复NameNode的全部数据,那如何保证NameNode数据存储安全
这个问题就要说NameNode的高可用了,即 NameNode HA。
一个NameNode有单点故障的问题,那就配置双NameNode,配置有两个关键点,一是必须要保证这两个NameNode的元数据信息必须要同步的,二是一个NameNode挂掉之后另一个要立马补上。
1.元数据信息同步在 HA 方案中采用的是“共享存储”。每次写文件时,需要将日志同步写入共享存储,这个步骤成功才能认定写文件成功。然后备份节点定期从共享存储同步日志,以便进行主备切换。
2.监控NameNode状态采用zookeeper,两个NameNode节点的状态存放在zookeeper中,另外两个NameNode节点分别有一个进程监控程序,实施读取zookeeper中有NameNode的状态,来判断当前的NameNode是不是已经down机。如果Standby的NameNode节点的ZKFC发现主节点已经挂掉,那么就会强制给原本的Active NameNode节点发送强制关闭请求,之后将备用的NameNode设置为Active。
如果面试官再问HA中的 共享存储 是怎么实现的知道吗?
可以进行解释下:NameNode 共享存储方案有很多,比如Linux HA, VMware FT, QJM等,目前社区已经把由Clouderea公司实现的基于QJM(Quorum Journal Manager)的方案合并到HDFS的trunk之中并且作为默认的共享存储实现。
基于QJM的共享存储系统主要用于保存EditLog,并不保存FSImage文件。FSImage文件还是在NameNode的本地磁盘上。
QJM共享存储的基本思想来自于Paxos算法,采用多个称为JournalNode的节点组成的JournalNode集群来存储EditLog。每个JournalNode保存同样的EditLog副本。每次NameNode写EditLog的时候,除了向本地磁盘写入 EditLog 之外,也会并行地向JournalNode集群之中的每一个JournalNode发送写请求,只要大多数的JournalNode节点返回成功就认为向JournalNode集群写入EditLog成功。如果有2N+1台JournalNode,那么根据大多数的原则,最多可以容忍有N台JournalNode节点挂掉。
7. 在NameNode HA中,会出现脑裂问题吗?怎么解决脑裂
假设 NameNode1 当前为 Active 状态,NameNode2 当前为 Standby 状态。如果某一时刻 NameNode1 对应的 ZKFailoverController 进程发生了“假死”现象,那么 Zookeeper 服务端会认为 NameNode1 挂掉了,根据前面的主备切换逻辑,NameNode2 会替代 NameNode1 进入 Active 状态。但是此时 NameNode1 可能仍然处于 Active 状态正常运行,这样 NameNode1 和 NameNode2 都处于 Active 状态,都可以对外提供服务。这种情况称为脑裂。
脑裂对于NameNode这类对数据一致性要求非常高的系统来说是灾难性的,数据会发生错乱且无法恢复。zookeeper社区对这种问题的解决方法叫做 fencing,中文翻译为隔离,也就是想办法把旧的 Active NameNode 隔离起来,使它不能正常对外提供服务。
在进行 fencing 的时候,会执行以下的操作:
1.首先尝试调用这个旧 Active NameNode 的 HAServiceProtocol RPC 接口的 transitionToStandby 方法,看能不能把它转换为 Standby 状态。
2.如果 transitionToStandby 方法调用失败,那么就执行 Hadoop 配置文件之中预定义的隔离措施,Hadoop 目前主要提供两种隔离措施,通常会选择 sshfence:
sshfence:通过 SSH 登录到目标机器上,执行命令 fuser 将对应的进程杀死;
shellfence:执行一个用户自定义的 shell 脚本来将对应的进程隔离。
8. 小文件过多会有什么危害,如何避免
Hadoop上大量HDFS元数据信息存储在NameNode内存中,因此过多的小文件必定会压垮NameNode的内存。
每个元数据对象约占150byte,所以如果有1千万个小文件,每个文件占用一个block,则NameNode大约需要2G空间。如果存储1亿个文件,则NameNode需要20G空间。
显而易见的解决这个问题的方法就是合并小文件,可以选择在客户端上传时执行一定的策略先合并,或者是使用Hadoop的CombineFileInputFormat<K,V>实现小文件的合并。
9. 请说下HDFS的组织架构
1.Client:客户端
切分文件。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行存储
与NameNode交互,获取文件的位置信息
与DataNode交互,读取或者写入数据
Client提供一些命令来管理HDFS,比如启动关闭HDFS、访问HDFS目录及内容等
2.NameNode:名称节点,也称主节点,存储数据的元数据信息,不存储具体的数据
管理HDFS的名称空间
管理数据块(Block)映射信息
配置副本策略
处理客户端读写请求
3.DataNode:数据节点,也称从节点。NameNode下达命令,DataNode执行实际的操作
存储实际的数据块
执行数据块的读/写操作
4.Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务
辅助NameNode,分担其工作量
定期合并Fsimage和Edits,并推送给NameNode
在紧急情况下,可辅助恢复NameNode
10. 请说下MR中Map Task的工作机制
简单概述:
inputFile通过split被切割为多个split文件,通过Record按行读取内容给map(自己写的处理逻辑的方法) ,数据被map处理完之后交给OutputCollect收集器,对其结果key进行分区(默认使用的hashPartitioner),然后写入buffer,每个map task 都有一个内存缓冲区(环形缓冲区),存放着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式溢写到磁盘,当整个map task 结束后再对磁盘中这个maptask产生的所有临时文件做合并,生成最终的正式输出文件,然后等待reduce task的拉取。
详细步骤:
1.读取数据组件 InputFormat (默认 TextInputFormat) 会通过 getSplits 方法对输入目录中的文件进行逻辑切片规划得到 block,有多少个 block就对应启动多少个 MapTask。
2.将输入文件切分为 block 之后,由 RecordReader 对象 (默认是LineRecordReader) 进行读取,以 \n 作为分隔符, 读取一行数据, 返回 <key,value>, Key 表示每行首字符偏移值,Value 表示这一行文本内容。
3.读取 block 返回 <key,value>, 进入用户自己继承的 Mapper 类中,执行用户重写的 map 函数,RecordReader 读取一行这里调用一次。
4.Mapper 逻辑结束之后,将 Mapper 的每条结果通过 context.write 进行collect数据收集。在 collect 中,会先对其进行分区处理,默认使用 HashPartitioner。
5.接下来,会将数据写入内存,内存中这片区域叫做环形缓冲区(默认100M),缓冲区的作用是 批量收集 Mapper 结果,减少磁盘 IO 的影响。我们的 Key/Value 对以及 Partition 的结果都会被写入缓冲区。当然,写入之前,Key 与 Value 值都会被序列化成字节数组。
6.当环形缓冲区的数据达到溢写比列(默认0.8),也就是80M时,溢写线程启动,需要对这 80MB 空间内的 Key 做排序 (Sort)。排序是 MapReduce 模型默认的行为,这里的排序也是对序列化的字节做的排序。
7.合并溢写文件,每次溢写会在磁盘上生成一个临时文件 (写之前判断是否有 Combiner),如果 Mapper 的输出结果真的很大,有多次这样的溢写发生,磁盘上相应的就会有多个临时文件存在。当整个数据处理结束之后开始对磁盘中的临时文件进行 Merge 合并,因为最终的文件只有一个写入磁盘,并且为这个文件提供了一个索引文件,以记录每个reduce对应数据的偏移量。
11. 请说下MR中Reduce Task的工作机制
简单描述:
Reduce 大致分为 copy、sort、reduce 三个阶段,重点在前两个阶段。
copy 阶段包含一个 eventFetcher 来获取已完成的 map 列表,由 Fetcher 线程去 copy 数据,在此过程中会启动两个 merge 线程,分别为 inMemoryMerger 和 onDiskMerger,分别将内存中的数据 merge 到磁盘和将磁盘中的数据进行 merge。待数据 copy 完成之后,copy 阶段就完成了。
开始进行 sort 阶段,sort 阶段主要是执行 finalMerge 操作,纯粹的 sort 阶段,完成之后就是 reduce 阶段,调用用户定义的 reduce 函数进行处理。
详细步骤:
1.Copy阶段:简单地拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求maptask获取属于自己的文件(map task 的分区会标识每个map task属于哪个reduce task ,默认reduce task的标识从0开始)。
2.Merge阶段:在远程拷贝数据的同时,ReduceTask启动了两个后台线程对内存和磁盘上的文件进行合并,以防止内存使用过多或磁盘上文件过多。
merge有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的数据量到达一定阈值,就直接启动内存到磁盘的merge。与map端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。内存到磁盘的merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge方式生成最终的文件。
3.合并排序:把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。
4.对排序后的键值对调用reduce方法:键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到HDFS文件中。
12. 请说下MR中Shuffle阶段
shuffle阶段分为四个步骤:依次为:分区,排序,规约,分组,其中前三个步骤在map阶段完成,最后一个步骤在reduce阶段完成。
shuffle 是 Mapreduce 的核心,它分布在 Mapreduce 的 map 阶段和 reduce 阶段。一般把从 Map 产生输出开始到 Reduce 取得数据作为输入之前的过程称作 shuffle。
1.Collect阶段:将 MapTask 的结果输出到默认大小为 100M 的环形缓冲区,保存的是 key/value,Partition 分区信息等。
2.Spill阶段:当内存中的数据量达到一定的阀值的时候,就会将数据写入本地磁盘,在将数据写入磁盘之前需要对数据进行一次排序的操作,如果配置了 combiner,还会将有相同分区号和 key 的数据进行排序。
3.MapTask阶段的Merge:把所有溢出的临时文件进行一次合并操作,以确保一个 MapTask 最终只产生一个中间数据文件。
4.Copy阶段:ReduceTask 启动 Fetcher 线程到已经完成 MapTask 的节点上复制一份属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值的时候,就会将数据写到磁盘之上。
5.ReduceTask阶段的Merge:在 ReduceTask 远程复制数据的同时,会在后台开启两个线程对内存到本地的数据文件进行合并操作。
6.Sort阶段:在对数据进行合并的同时,会进行排序操作,由于 MapTask 阶段已经对数据进行了局部的排序,ReduceTask 只需保证 Copy 的数据的最终整体有效性即可。
Shuffle 中的缓冲区大小会影响到 mapreduce 程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快。
缓冲区的大小可以通过参数调整, 参数:mapreduce.task.io.sort.mb 默认100M
13. Shuffle阶段的数据压缩机制了解吗
在shuffle阶段,可以看到数据通过大量的拷贝,从map阶段输出的数据,都要通过网络拷贝,发送到reduce阶段,这一过程中,涉及到大量的网络IO,如果数据能够进行压缩,那么数据的发送量就会少得多。
hadoop当中支持的压缩算法:
gzip、bzip2、LZO、LZ4、Snappy,这几种压缩算法综合压缩和解压缩的速率,谷歌的Snappy是最优的,一般都选择Snappy压缩。谷歌出品,必属精品。
14. 在写MR时,什么情况下可以使用规约
规约(combiner)是不能够影响任务的运行结果的局部汇总,适用于求和类,不适用于求平均值,如果reduce的输入参数类型和输出参数的类型是一样的,则规约的类可以使用reduce类,只需要在驱动类中指明规约的类即可。
15. YARN集群的架构和工作原理知道多少
YARN的基本设计思想是将MapReduce V1中的JobTracker拆分为两个独立的服务:ResourceManager和ApplicationMaster。
ResourceManager负责整个系统的资源管理和分配,ApplicationMaster负责单个应用程序的的管理。
1.ResourceManager: RM是一个全局的资源管理器,负责整个系统的资源管理和分配,它主要由两个部分组成:调度器(Scheduler)和应用程序管理器(Application Manager)。
调度器根据容量、队列等限制条件,将系统中的资源分配给正在运行的应用程序,在保证容量、公平性和服务等级的前提下,优化集群资源利用率,让所有的资源都被充分利用应用程序管理器负责管理整个系统中的所有的应用程序,包括应用程序的提交、与调度器协商资源以启动ApplicationMaster、监控ApplicationMaster运行状态并在失败时重启它。
2.ApplicationMaster: 用户提交的一个应用程序会对应于一个ApplicationMaster,它的主要功能有:
与RM调度器协商以获得资源,资源以Container表示。
将得到的任务进一步分配给内部的任务。
与NM通信以启动/停止任务。
监控所有的内部任务状态,并在任务运行失败的时候重新为任务申请资源以重启任务。
3.NodeManager: NodeManager是每个节点上的资源和任务管理器,一方面,它会定期地向RM汇报本节点上的资源使用情况和各个Container的运行状态;另一方面,他接收并处理来自AM的Container启动和停止请求。
4.Container: Container是YARN中的资源抽象,封装了各种资源。一个应用程序会分配一个Container,这个应用程序只能使用这个Container中描述的资源。不同于MapReduceV1中槽位slot的资源封装,Container是一个动态资源的划分单位,更能充分利用资源。
16. YARN的任务提交流程是怎样的
当jobclient向YARN提交一个应用程序后,YARN将分两个阶段运行这个应用程序:一是启动ApplicationMaster;第二个阶段是由ApplicationMaster创建应用程序,为它申请资源,监控运行直到结束。 具体步骤如下:
1.用户向YARN提交一个应用程序,并指定ApplicationMaster程序、启动ApplicationMaster的命令、用户程序。
2.RM为这个应用程序分配第一个Container,并与之对应的NM通讯,要求它在这个Container中启动应用程序ApplicationMaster。
3.ApplicationMaster向RM注册,然后拆分为内部各个子任务,为各个内部任务申请资源,并监控这些任务的运行,直到结束。
4.AM采用轮询的方式向RM申请和领取资源。
5.RM为AM分配资源,以Container形式返回。
6.AM申请到资源后,便与之对应的NM通讯,要求NM启动任务。
7.NodeManager为任务设置好运行环境,将任务启动命令写到一个脚本中,并通过运行这个脚本启动任务。
8.各个任务向AM汇报自己的状态和进度,以便当任务失败时可以重启任务。
9.应用程序完成后,ApplicationMaster向ResourceManager注销并关闭自己。
17. YARN的资源调度三种模型了解吗
在Yarn中有三种调度器可以选择:FIFO Scheduler ,Capacity Scheduler,Fair Scheduler。
Apache版本的hadoop默认使用的是Capacity Scheduler调度方式。CDH版本的默认使用的是Fair Scheduler调度方式
FIFO Scheduler(先来先服务):
FIFO Scheduler把应用按提交的顺序排成一个队列,这是一个先进先出队列,在进行资源分配的时候,先给队列中最头上的应用进行分配资源,待最头上的应用需求满足后再给下一个分配,以此类推。
FIFO Scheduler是最简单也是最容易理解的调度器,也不需要任何配置,但它并不适用于共享集群。大的应用可能会占用所有集群资源,这就导致其它应用被阻塞,比如有个大任务在执行,占用了全部的资源,再提交一个小任务,则此小任务会一直被阻塞。
Capacity Scheduler(能力调度器):
对于Capacity调度器,有一个专门的队列用来运行小任务,但是为小任务专门设置一个队列会预先占用一定的集群资源,这就导致大任务的执行时间会落后于使用FIFO调度器时的时间。
Fair Scheduler(公平调度器):
在Fair调度器中,我们不需要预先占用一定的系统资源,Fair调度器会为所有运行的job动态的调整系统资源。
比如:当第一个大job提交时,只有这一个job在运行,此时它获得了所有集群资源;当第二个小任务提交后,Fair调度器会分配一半资源给这个小任务,让这两个任务公平的共享集群资源。
需要注意的是,在Fair调度器中,从第二个任务提交到获得资源会有一定的延迟,因为它需要等待第一个任务释放占用的Container。小任务执行完成之后也会释放自己占用的资源,大任务又获得了全部的系统资源。最终的效果就是Fair调度器即得到了高的资源利用率又能保证小任务及时完成。