当前位置:   article > 正文

大数据Hadoop、Hive、Kafka、Hbase、Spark等框架面经_hadoop面经

hadoop面经

大数据组件

在这里插入图片描述
学习路线:
阶段1:学习绿色箭头的知识点;
阶段2:学习红色箭头的知识点;
阶段3:学习蓝色箭头的知识点;

1 Hadoop

1.1 Hadoop1.x与Hadoop2.x的区别

在这里插入图片描述

1.2 HDFS架构

(1)NameNode(nn):存储文件的元数据,如文件名、文件目录结构、文件属性(生成时间、副本数、文件权限)、以及每个文件的块列表和块所在的DataNode;
(2)DataNode:在本地文件系统存储文件块数据,以及块数据的校验和;
(3)SecondaryNameNode(2nn):每隔一段时间对NameNode元数据进行备份;

HDFS优缺点:
优点:
1.高容错性
2.适合处理大数据
3.可构建在廉价机器上
缺点:
1.不适合低延迟数据访问
2.无法高效的对大量小文件进行存储
3.不支持并发写入,文件随机修改

1.3 Yarn架构概述

(1)ResourceManager:处理客户端请求、监控NodeManager、启动或监控ApplicationMaster、资源的分配与调度;
(2)NodeManager:管理单个节点上的资源、处理来自ResourceManager的命令、处理来自ApplicationMaster的命令;
(3)ApplicationMaster:负责数据的切分、为应用程序申请资源并分配给内部任务、任务的监控与容错;
(4)Container:是Yarn中的资源抽象对象,如内存、CPU、硬盘、网络等;

1.4 HDFS块大小

默认大小在Hadoop2.x是128M、Hadoop1.x是64M。
在这里插入图片描述
块大小=传输时间×传输速率

为什么HDFS块大小不能设置太小,也不能设置太大?
(1)HDFS的块设置太小,会增加寻址时间,程序会一直寻找块的开始位置;
(2)设置太大,从磁盘传输数据的时间会明显大于定位这个块所需的时间。导致程序在处理这块数据的时候会非常慢;

1.5 HDFS写数据流程

在这里插入图片描述
(1)客户端通过分布式文件系统(DistributedFileSystem)模块向NameNode请求上传文件,这时NameNode会检查是否有权限上传以及检查目标文件是否已存在;
(2)NameNode返回检查的结果,响应是否可以上传;
(3)NameNode返回可以上传的响应,那么客户端将请求第一个Block,并询问NameNode服务器数据具体上传到哪几台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步骤;

1.6 HDFS读数据流程

在这里插入图片描述
(1)客户端通过分布式文件系统(DistributedFileSystem)向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址;
(2)根据集群拓扑结构得出DataNode与客户端的距离,然后进行排序,挑选一台距离较近的DataNode服务器节点,然后请求读取数据;
(3)这时候,DataNode节点就开始从磁盘里面读取数据到输入流中,并Packet(默认大小64k)为单位传输给客户端;
(4)客户端以Packet为单位进行接收,先在本地进行缓存,都全部读完之后,最后再将数据写入到目标文件中;

1.7 HDFS的副本放置策略(副本存储节点选择)

以下是以Hadoop3.1.3版本(与Hadoop2.7版本之前的不同):
(1)第一个副本在client所处的节点上,如果client在集群外,随机选一个;
(2)第二个副本存放在与第一个节点不同机架中的一个节点上;
(3)第三个副本和第二个在同一个机架,随机放在不同的节点上;

1.8 HDFS是如何保证数据可靠性的?

(1)安全模式
①HDFS刚启动时,NameNode进入安全模式,处于安全模式的NameNode不能做任何的文件操作,甚至内部的副本创建也是不允许的,NameNode这时需要和各个DataNode进行通信,获得DataNode存储的数据块信息,并对数据块信息进行检查,只有通过了NameNode的检查,一个数据块才被认为是安全的。当认为安全的数据块所占比例达到了某个阈值,NameNode才会开始启动;
(2)SecondaryNamenode备份机制
①在Hadoop中使用SecondaryNameNode来备份NameNode的元数据,以防止在NameNode宕机的时候,能从SecondaryNameNode中恢复出NameNode上的元数据;
②NameNode中保存了整个文件系统的元数据,而SecondaryNameNode的作用就是周期性保存NameNode的元数据。元数据中包括FSImage镜像文件数据和EditLog编辑日志。FSImage相当于HDFS的检查点,NameNode启动时候会读取FSImage的内容到内存,并将其与EditLog日志中的所有修改信息合并生成新的FSImage。在NameNode运行过程中,所有关于HDFS的修改都将写入EditLog日志文件中。这样,如果NameNode宕机,可以通过SecondaryNameNode中保存的FSImage和EditLog数据恢复出NameNode最近的状态,尽量减少数据的损失;
(3)心跳机制和副本重新创建
①为了保证NameNode和各个DataNode的联系,HDFS采用了心跳机制。NameNode周期性的向各个DataNode发送心跳包,而收到心跳包的DataNode要进行回复。因为心跳包是定时发送的,所以NameNode就把要执行的命令也通过心跳包发送给DataNode,而DataNode收到心跳包,一方面要回复NameNode,另一方面就要开始应用数据的传输;
②如果检测到DataNode失效,NameNode之前保存在这个DataNode上的数据就变成不可用数据。如果有的副本存储在失效的DataNode上,那么需要重新创建这个副本,放到另外可用的地方去;
(4)数据一致性
①一般来讲,DataNode与应用交互的大部分情况都是通过网络进行的,而网络数据传输带来的一大问题就是数据是否原样到达。为了保证数据的一致性,HDFS采用了数据校验和(checkSum)机制。创建文件时,HDFS会为这个文件生成一个校验和,校验和文件和文件本身保存在同一空间中。传输数据时会将数据与校验和数据一起传输,应用收到数据后可以进行校验,如果两个校验的结果不同,则文件出错了,这个数据块就变成无效的。如果判定为无效,则需要从其他DataNode上读取副本数据;

1.9 什么是MapReduce

MapReduce是一个分布式计算框架,用于编写批处理应用程序。编写好的程序可以提交到Hadoop集群上用于处理大规模的数据集。

1.10 MapReduce详细工作流程

在这里插入图片描述

在这里插入图片描述

一个完整的MapReduce程序在分布式运行时有3类实例进程,5大步骤:
3类实例进程:

  1. MRAppMaster:负责整个程序的过程调度及状态协调;
  2. MapTask:负责map阶段的整个数据处理流程;
  3. ReduceTask:负责reduce阶段的整个数据处理流程;

5大步骤:input->map->shuffle->reduce->output;

(1)首先,在客户端执行submit()方法之前,会先去获取一下待读取文件的信息;
(2)然后,客户端向Yarn集群提交切片信息(job.split)、wc.jar、job.xml,并调用ResourceManager来创建MRAppMaster进程,这时候MRAppMaster进程会根据文件的切片信息去计算到底需要创建几个MapTask进程;
(3)接着,MapTask进程开始工作,每个MapTask从文件中读取各自所需处理的数据,读取的方式采用的是TextInputFormat(默认格式,可以自定义),在TextInputFormat里面再去调用RecorderReader方法来进行读取,每读取一行之后返回给mapper类;
(4)在mapper类中调用map()方法,对每一行数据进行相关的逻辑运算,当数据处理完后,将数据传到分区方法中,对数据进行分区标注后,最后再将数据发送到环形缓冲区中,也就是Shuffle阶段的开始;
(5)数据进入到环形缓冲区之后,环形缓冲区的大小默认是100MB,阈值是80%,当达到阈值的时候开始溢写,在溢写之前会数据进行排序,排序按照对key的索引进行字典顺序排序,排序的手段是快排,排完序之后就开始溢写;
(6)当所有的数据都溢写到文件之后,会对同一个分区内溢写出的多个有序的结果文件合并成一个大的溢写文件(默认10个溢写文件合并成一个大文件)并且完成归并排序,之后写入到磁盘等待Reduce端来拉取数据;
(7)ReduceTask根据自己的分区号,去各个MapTask机器上拷贝相应分区内的数据到本地内存缓冲区,内存不够的话就溢写到磁盘。当所有数据拷贝完毕之后,ReduceTask会将这些文件再进行归并排序,排好序之后按照相同的key进行分组,至此Shuffle的过程基本结束;
(9)在分组之后,一次读取一组数据到Reducer类中,调用reduce()方法进行聚合处理,处理完之后,最后再通过context.write(),默认以TextOutputFormat格式,经RecordWriter写出到文件中,此时就完成了整个MapReduce过程;

1.11 为什么Shuffle过程需要进行排序?

1.11.1 为什么Map阶段需要进行排序?

由于mapreduce程序在reduce阶段需要分组,将key相同的放在一起进行规约,为了达到这个目的,需要对数据进行排序。而在map阶段,key存在combine操作,排序之后相同的key放到一块显然更方便做合并操作。而且,在map端进行提前排序,目的也是为了减轻reduce端排序的压力;

1.11.2 为什么Reduce阶段需要进行排序?

在Reduce端中,reduce task是按照key去处理数据的,如果没有排序,那必须从所有数据中,把当前相同key的所有value数据给取出来,然后进行reduce的逻辑处理。显然,每个key到这个逻辑,都是需要做一次全量数据扫描,严重影响性能,有了排序之后,很方便的得到一个key对应的value集合;

1.12 MapReduce的Shuffle过程

1.12.1 Shuffle阶段

Shuffle阶段:在map方法之后reduce方法之前这段处理过程叫Shuffle。

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

1.12.2 为什么环形缓冲区的阈值是80%?

环形缓冲区是有大小限制的,默认是100MB。当map task的输出结果很多时,可能会撑爆内存,所以需要在一定条件下将环形缓冲区中的数据临时写入到磁盘中,然后再重新利用这块环形缓冲区。从内存往磁盘写数据的过程叫做溢写,溢写是由单独线程来完成,不影响往环形缓冲区写map结果的线程。溢写线程启动时不会阻止map的结果输出,所以整个环形缓冲区有个溢写的比例spill.percent,默认是0.8,也就是当环形缓冲区的数据已经达到阈值(buffer size * spill percent = 100MB * 0.8 = 80MB),溢写线程开始启动,锁定这80MB的内存,执行溢写过程,map task的输出结果还可以往剩下的20MB内存中继续写,互不影响;

1.13 MapReduce优化

1.13.1 小文件优化

Hadoop适合大文件的处理和存储,但是不适合小文件?为什么?
存储方面:
hadoop的存储每个文件都会在NameNode上记录元数据,如果小文件过多,造成NameNode的压力。
读取方面:
同样大小的文件分为很多小文件的话,会增加磁盘寻址次数,降低性能。
计算方面:
一个map默认处理一个分片或者一个小文件,如果map的启动时间都比数据处理的时间还要长,那么就会造成性能低,而且在map端溢写磁盘的时候每一个map最终会产生reduce数量个数的中间结果,如果map数量特别多,就会造成临时文件很多,而且在reduce拉取数据的时候增加磁盘的IO。

解决方法:
1、从源头干掉,也就是在hdfs上我们不存储小文件,在数据上传hdfs的时候我们就合并小文件,对小文件进行归档(Har)、自定义Inputformat将小文件存储成SequenceFile 文件;
2、在FileInputFormat读取入数据的时候我们使用实现类CombineFileInputFormat读取数据,在读取数据的时候进行合并,解决输入端大量小文件场景;
3、对于大量小文件Job,可以开启JVM重用;

1.13.2 数据倾斜问题优化

1、既然默认的是hash算法进行分区,那我们自定义分区,修改分区实现逻辑,结合业务特点,使得每个分区数据基本平衡
2、既然有默认的分区算法,那么我们可以修改分区的键,让其符合hash分区,并且使得最后的分区平衡,比如在key前加随机数。
3、既然reduce处理慢,我们可以增加reduce的内存和核数,这样可以提高一点性能,虽然没从根本上解决问题,但是还有效果。
4、既然一个reduce处理慢,那我们可以增加reduce的个数来分摊一些压力呀,虽然也不能从根本上解决问题,还是有一定的效果。

1.14 如何能够让Map执行效率最高

思想:尽量减少环形缓冲区溢写的次数,减少IO的使用。

1、调大环形缓冲区的大小,将100MB调更大。
2、调大环形缓冲区阈值(80%)的大小。
3、对Map输出的数据进行压缩。
4、不影响实际业务的前提下,采用Combiner提前合并,减少磁盘I/O。

1.15 如何能够让Reduce执行效率最高

1、尽量减少环形缓冲区溢写的次数
2、尽量将所有的数据写入内存,在内存中进行计算。
  • 1
  • 2

1.16 MapReduce程序的常用数据序列化类型

在这里插入图片描述

1.17 Yarn的工作流程

在这里插入图片描述

注意点说明:
1.Yarn Job执行的过程中,只会在某一个NodeManager节点上开启一个名为MRAppMaster的进程;
2.MRAppMaster进程的作用是:
(1)为所有的NodeManager执行任务向ResourceManager申请资源(CPU+内存+网络等);
(2)触发任务(MapTask,ReduceTask)的正式执行;
3.真正负责计算的进程名为YarnChild,NodeManager是YarnChild进程的守护进程,负责监控YarnChild的运行状态;
4.Yarn Job执行完毕之后,诸如YarnChild,MRAppMaster进程都会结束,但是,ResouceManager,NodeManager进程一直处于待命状态,等待下一个Yarn Job任务的到来;
5.Container不是一个进程,Container中记录了MRAppMaster进程向RM进程申请的资源信息,申请的资源最终是给YarnChild进程使用的;

Yarn的工作流程:
(1)首先,客户端向整个集群提交MapReduce作业,并向ResouceManager申请一个作业id;
(2)然后,ResouceManager给客户端返回该作业资源的提交路径和作业id;
(3)这时候,客户端根据ResouceManager返回来作业提交路径,将jar包、切片信息和配置文件信息提交到指定路径下;
(4)当客户端提交完资源后,开始向ResouceManager申请运行MRAppMaster;
(5)ResouceManager收到客户端的请求之后,会将客户端提交的job初始化成一个个task,并且放入到容量调度器中;
(6)当某一个空闲的NodeManager领取到该作业之后,该NodeManager就开始创建Container容器,启动MRAppMaster进程,并且下载客户端提交的资源到本地;
(7)接着,MRAppMaster进程向ResouceManager申请运行多个MapTask任务资源;
(8)ResouceManager将运行的MapTask任务分配给空闲的NodeManager,NodeManager分别领取到任务后,开始创建容器,并且启动运行MapTask任务;
(9)当所有的MapTask任务运行完成之后,MRAppMaster进程向ResouceManager申请运行多个ReduceTask任务资源;
(10)当所有的ReduceTask任务运行完毕之后,MapReduce程序会向ResouceManager申请注销自己,并释放资源;

1.18 Yarn的资源调度器

调度器:用来对Hadoop分布式集群中同一时刻运行的Job进行规划和约束的。

Yarn的资源调度器有以下三种方式:
(1)FIFO:ResourceManager中维护着一个Queue,这个queue中同一时刻只有一个Job处于运行状态。
(2)容量调度器(默认的方式):.ResourceManager中维护着多个Queue,每个queue中同一时刻只有一个Job处于运行状态。并发数(同一时刻运行的Job数)= 队列数。
(3)公平调度器:ResourceManager中维护着多个Queue,每个queue中同一时刻可以执行多个Job。并发数(同一时刻运行的Job数)>= 队列数。

1.19 Hadoop解决数据倾斜方法

1.19.1 什么叫数据倾斜?

MapReduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜;

1.19.2 解决数据倾斜的方法

1)提前在map进行combine,减少传输的数据量

在mapper加上combiner相当于提前进行reduce,即把一个mapper中的相同key进行了聚合,减少shuffle过程中传输的数据量,以及reducer端的计算量。但是,如果导致数据倾斜的key大量分布在不同的mapper的时候,这种方法就不是很有效了。

2)导致数据倾斜的key 大量分布在不同的mapper

(1)局部聚合加全局聚合。
第一次在map阶段对那些导致了数据倾斜的key 加上1到n的随机前缀,这样本来相同的key 也会被分到多个Reducer中进行局部聚合,数量就会大大降低。
第二次mapreduce,去掉key的随机前缀,进行全局聚合。
思想:二次mr,第一次将key随机散列到不同reducer进行处理达到负载均衡目的。第二次再根据去掉key的随机前缀,按原key进行reduce处理。这个方法进行两次mapreduce,性能稍差。
(2)增加Reducer,提升并行度
JobConf.setNumReduceTasks(int)
(3)实现自定义分区
根据数据分布情况,自定义散列函数,将key均匀分配到不同Reducer

1.20 NameNode与SecondaryNameNode的区别与联系

(1)区别:
①NameNode负责管理整个文件系统的元数据,以及每一个路径所对应的数据块信息;
②SecondaryNameNode主要用于定期合并命名空间镜像和命名空间镜像的编辑日志;
(2)联系:
①SecondaryNameNode中保存了一份和NameNode一致的镜像文件(fsimage)和编辑日志(edits);
②在主NameNode发生故障的时候,可以从SecondaryNameNode恢复数据;

1.21 SecondaryNameNode的工作机制

(1)角色:SecondaryNameNode每隔一段时间对NameNode的元数据进行备份;
(2)具体的工作机制:
①SecondaryNameNode询问NameNode是否需要checkpoint,直接带回NameNode是否检查结果;
②SecondaryNameNode请求执行checkpoint;
③NameNode滚动正在写的Edits日志;
④将滚动前的编辑日志和镜像文件拷贝到SecondaryNameNode;
⑤SecondaryNameNode加载编辑日志和镜像文件到内存,并合并;
⑥生成新的镜像文件fsimage.checkpoint;
⑦拷贝fsimage.checkpoint到NameNode;
⑧NameNode将fsimage.checkpoint重新命名成fsimage;
(3)总结:所以如果NameNode中的元数据丢失,是可以从SecondaryNameNode恢复一部分元数据信息的,但是不是全部,因为NameNode正在写的edits日志还没拷贝到SecondaryNameNode,这部分恢复不了;

1.22 NameNode在启动的时候会做哪些操作?

NameNode 数据存储在内存和本地磁盘,本地磁盘数据存储在fsimage镜像文件和edits编辑日志文件;

fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息;
edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到edits文件中;

(1)首次启动
①格式化系统,为了生成fsimage镜像文件;
②启动NameNode
1)读取fsimage文件,将文件内容加载进内存中;
2)等待DataNode注册与发送block report;
③启动DataNode
1)向NameNode注册;
2)发送block report;
3)检查fsimage中记录的块的数量和block report 中的块的总数是否相同;
④对文件系统进行操作(创建目录、上传文件、删除文件等)
1)此时内存中已经有文件系统改变的信息,但是磁盘中没有文件系统改变的信息,此时将这些改变信息写入edits文件中,edits文件中存储的是文件系统元数据改变的信息;

(2)第二次启动
①读取fsimage和edits文件;
②将fsimage和edits文件合并成新的fsimage文件;
③创建新的edits文件,内容为空;
④启动DataNode;

1.23 HDFS在读写过程中,如果其中一台DataNode突然宕机了怎么办?

客户端在读写数据时,与DataNode建立管道(pipeline),管道正向是客户端向DataNode发送数据包,管道反向是DataNode向客户端发送Ack确认,也就是正确接收到数据包之后发送一个已确认接收到的应答,当DataNode突然挂掉了,客户端接收不到这个DataNode发送的Ack确认,客户端就会通知NameNode,NameNode检查该块的副本与规定的不符,那么NameNode就会通知DataNode去复制副本,并将挂掉的DataNode作下线处理,不再让它参与文件的读写操作;

1.24 NameNode宕机怎么解决?

首先分析宕机后的损失,宕机后直接导致client无法访问,内存中的元数据丢失,但是硬盘中的元数据应该还存在,如果只是节点挂了,重启即可,但如果是机器挂了,重启机器后看节点是否能重启,不能重启就要找到原因,进行修复。但是最终的解决方案应该是在设计集群的初期就考虑到这个问题,做NameNode的HA;

1.25 SecondaryNameNode不能恢复NameNode的全部数据,那如何保证NameNode数据存储的安全性?

这个问题就要说NameNode的高可用了,即NameNode HA;
一个NameNode有单节点故障问题,那就配置双NameNode,配置有两个关键点:
① 必须保证这两个NameNode的元数据信息必须是同步的;
② 如果其中一个NameNode挂掉之后,另外一个NameNode要立马补上;

两个NameNode之间的元数据时如何保证同步的?
1)两个NameNode元数据信息的一致性保证采用的是“共享存储”,也就是说两个NameNode都需要与一组Journal Node节点保持通信。当Active NameNode节点执行的读写操作对NameSpace(目录树)有所修改时,会确保将修改日志持久化到大部分的Journal Node节点上。而Standby NameNode发现NameSpace有所改动时,会从Journal Node 节点同步更改内容,进而保持与Active NameNode节点的数据一致;

一个NameNode挂掉之后,另外一个如何监听到并马上切换为Active(自动故障转移)?
1)监听NameNode状态采用的是Zookeeper,借助Zookeeper来实现自动故障转移,两个NameNode节点的状态存放在Zookeeper中,同时两个NameNode节点分别有一个ZKFC(ZooKeeperFailoverController )进程,实时读取Zookeeper中NameNode的状态,来判断当前的NameNode是不是宕机了。如果Standby的NameNode节点的ZKFC发现主节点已经挂掉了,那么就会首先给原本的Active NameNode节点发送强制关闭请求,之后将备用的NameNode设置为Active;

在HA中的“共享存储”是怎么实现的?
NameNode共享存储方案其实有很多,比如Linux HA、VMware FT、QJM等,目前Hadoop官网社区已经把由Cloudera公司实现的基于QJM(Quorum Journal Manager)的方案合并到HDFS的trunk之中并且作为默认的共享存储实现;
基于QJM的共享存储系统主要用于保存EditLog文件,并不保存FsImage文件。FsImage文件还是在本地磁盘上,QJM的共享存储思想来自于Paxos算法,采用多个称为JournalNode的节点组成的JournalNode集群来存储EditLog文件。每个JournalNode保存同样的EditLog副本,每次NameNode写EditLog的时候,除了向本地磁盘写入EditLog之外,也会并行的向JournalNode集群中的每一个JournalNode发送写请求,只要大多数的JournalNode节点返回成功就认为向JournalNode集群写入EditLog成功。如果有2N+1台JournalNode,那么根据大多数的原则,最多可以容忍有N台JournalNode节点挂掉;

1.26 在NameNode HA中,会出现脑裂问题吗?怎么解决脑裂?

假设NameNode1当前为Active状态,NameNode2当前为Standby状态。如果某一时刻NameNode1对应的ZKFailoverController进程发生了“假死”现象,那么Zookeeper服务端则认为NameNode1挂掉了,根据主备切换逻辑,那么NameNode2会替代NameNode1进入Active状态,但是此时NameNode1可能仍然处于Active状态正常运行,这样NameNode1和NameNode2都处于Active状态,都可以对外提供服务。这种状况就叫做“脑裂”;

“脑裂”对应NameNode这类对数据一致性要求非常高的系统来说是灾难性的,数据会发生错乱且无法恢复;

Zookeeper社区对这种问题的解决方法是进行隔离(fencing),也就想办法把旧的Active NameNode隔离起来,使它不能正常对外提供服务;

在进行隔离(fencing)的时候会执行以下操作:
① 首先尝试调用旧的Active NameNode中的HAServiceProtocol RPC接口的transitionToStandby方法,看能不能把它转换为Standby状态;
② 如果transitionToStandby方法调用失败,那么就执行Hadoop配置文件之中的预定义隔离措施,Hadoop目前只要有两种隔离措施:ssh隔离、shell隔离;
1)ssh隔离:通过SSH登录到目标主机,指令kill -9 强制将NameNode进程杀死;
2)shell隔离:执行用于自定义的shell脚本来将对应的进程隔离;

1.27 NameNode、DataNode和Client三者之间协作关系及通信方式

NameNode可以看作是分布式文件系统中的管理者Master,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等,而且NameNode会将文件系统的元数据(meta-data)存储在内存中,这些信息主要包括了文件信息、每一个文件对应的文件块的信息以及每一个文件块所在DataNode的信息等;
DataNode是文件存储的基本单元,它将Block存储在本地文件系统中,保存了Block的(meta-data),同时周期性地将所有存在的Block信息发送给NameNode;
Client就是需要获取分布式文件系统文件的应用程序;
(1)文件写入
①客户端向NameNode发起文件写入的请求。NameNode根据文件大小和文件块的配置信息,返回给客户端所管理部分DataNode的信息。客户端将文件划分为多个Block,根据DataNode的地址信息,按顺序写入到每一个DataNode块中;
(2)文件读取
①客户端向NameNode发起文件读取的请求,NameNode返回文件存储的DataNode的信息,客户端读取文件信息;
(3)通信方式
①Client和NameNode之间是通过RPC(Remote Procedure Call)的方式进行通信;
②DataNode和NameNode之间是通过RPC的方式进行通信;
③Client和DataNode之间是通过简单的Socket方式进行通信;

1.28 MapReduce手写WordCount统计程序

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import javax.security.auth.login.Configuration;

public class Test {
   


    public static class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
   

        Text k = new Text();
        IntWritable v = new IntWritable(1);

        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
   
            // 1 获取一行
            String line = value.toString();
            // 2 切割
            String[] words = line.split(" ");
            // 3 输出
            for (String word : words) {
   
                k.set(word);
                context.write(k, v);
            }
        }
    }

    public static class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
   

        int sum;
        IntWritable v = new IntWritable();

        @Override
        protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
   
            // 1 累加求和
            sum = 0;
            for (IntWritable count : values) {
   
                sum += count.get();
            }
            // 2 输出
            v.set(sum);
            context.write(key, v);
        }
    }

    public static 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/519352
推荐阅读
相关标签
  

闽ICP备14008679号