hadoop分为三个组件
- HDFS负责海量数据的分布式存储 (存储数据)
- MapReduce是一个计算模型,负责海量数据的分布式计算 (计算,生产不用,设计理念指导其他框架,spark、flink )
- YARN主要负责集群资源的管理和调度
HDFS概念
分布式文件系统的特点:
1、分布式文件系统可以有效解决数据的存储和管理难题
2、将固定于某个地点的某个文件系统,扩展到任意多个地点/多个文件系统
3、众多的节点组成一个文件系统网络
4、每个节点可以分布在不同的地点,通过网络进行节点间的通信和数据传输
5、在使用分布式文件系统时,无需关心数据是存储在哪个节点上、或者是从哪个节点获取的,只需要像使用本地文件系统一样管理和存储文件系统中的数
Hadoop分布式文件系统(HDFS)是指被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统(Distributed File System)。
HDFS具有高度容错能力,旨在部署在低成本硬件上。
HDFS提供对应用程序数据的高吞吐量访问,适用于具有大型数据集的应用程序。
HDFS放宽了一些POSIX要求,以实现对文件系统数据的流式访问
HDFS优势:
1、可构建在廉价机器上,设备成本相对低 2、高容错性,HDFS将数据自动保存多个副本,副本丢失后,自动恢复,防止数据丢失或损坏 3、适合批处理,HDFS适合一次写入、多次查询(读取)的情况,适合在已有的数据进行多次分析,稳定性好 4、适合存储大文件,其中的大表示可以存储单个大文件,因为是分块存储,以及表示存储大量的数据
HDFS劣势:
1、由于提高吞吐量,降低实时性 2、由于每个文件都会在namenode中记录元数据,如果存储了大量的小文件,会对namenode造成很大的压力 3、不合适小文件处理,在mapreduce的过程中小文件的数量会造成map数量的增大,导致资源被占用,而且速度慢。 4、不适合文件的修改,文件只能追加在文件的末尾,不支持任意位置修改,不支持多个写入者操作
HDFS设计思路
1、存储超大文件
这里的“超大文件”是指几百MB、GB甚至TB级别的文件。
2、最高效的访问模式是 一次写入、多次读取(流式数据访问)
HDFS存储的数据集作为hadoop的分析对象。在数据集生成后,长时间在此数据集上进行各种分析。每次分析都将设计该数据集的大部分数据甚至全部数据,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。
3、运行在普通廉价的服务器上
HDFS设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。
如何实现的呢?
1.大文件被切割成小文件,使用分而治之的思想让很多服务器对同一个文件进行联合管理
2. 每个小文件做冗余备份,并且分散存到不同的服务器,做到高可靠不丢失
HDFS的基本框架图
HDFS具有主/从架构(master/slave架构)。HDFS集群由单个NameNode,和多个datanode构成。
1.数据块(block):块是文件存储处理的逻辑单元,HDFS的文件被分成块进行存储,块的大小是有一个参数的dfs.blocksize,默认大小在 hadoop2.x 版本中是 128M,老版本中是 64M,hadoop3.x版本中是128M,默认大小是可以调整的
dfs.blocksize 默认128MB
例子:一桶水1000ml ,瓶子的规格 100ml ==》 10瓶 一桶水1010ml,瓶子的规格100ml ==》 10+1瓶
200ml==》5+1瓶
比如:一个电影260M
1 128M
2 128M
3 4M
-----------------3块
伪分布式 1 DN节点,副本数1 :3个块,实际存储空间260M*1 = 260M
集群 3 DN节点,副本数3 :3*3个块,实际存储空间260M*3 = 780M
2.主节点NameNode(NN) 名称节点 老大(管理者) 读写请求先经过它,
NameNode(NN)是管理文件系统命名空间的主服务器和管理客户端对文件的访问组成,如打开,关闭和重命名文件和目录。负责管理文件目录、文件和block的对应关系以及block和datanode的对应关系,维护目录树,接管用户的请求.
文件包括:
① fsimage (文件系统镜像):元数据镜像文件。存储某一时段NameNode内存 元数据信息。
② edits: 操作日志文件。
③ fstime: 保存最近一次checkpoint的时间
3.DataNode (DN)数据节点 小弟(执行者) 存储数据 检索数据
负责管理它所在结点上存储的数据的读写,及存储数据。一般是文件系统客户端需要请求对指定数据结点进行读写操作,Datanode作为数据结点的服务进程来与文件系统客户端打交道
4.secondarynamenode 第二名节点 老二
只有在NameNode重启时,edits才会合并到fsimage文件中,从而得到一个文件系统的最新快照。但是在生产环境集群中的NameNode是很少重启的,这意味者当NameNode运行来很长时间后,edits文件会变的很大。在这种情况下就会出现下面这些问题:
- edits文件会变的很大,如何去管理这个文件?
- NameNode的重启会花费很长的时间,因为有很多改动要合并到fsimage文件上。
- 如果NameNode宕掉了,那我们就丢失了很多改动,因为此时的fsimage文件时间戳比较旧。
因此为了克服这个问题,我们需要一个易于管理的机制来帮助我们减小edits文件的大小和得到一个最新的fsimage文件,这样也会减小在NameNode上的压力。而Secondary NameNode就是为了帮助解决上述问题提出的,它的职责是合并NameNode的edits到fsimage文件中。如图所示:
上图是工secondarynamenode作原理
- 首先,它定时到NameNode去获取edits,并更新到fsimage上。
- 一旦它有新的fsimage文件,它将其拷贝回NameNode上。
- NameNode在下次重启时回使用这个新的fsimage文件,从而减少重启的时间。
Secondary NameNode的整个目的在HDFS中提供一个Checkpoint Node,通过阅读官方文档可以清晰的知道,它只是NameNode的一个助手节点,这也是它在社区内被认为是Checkpoint Node的原因。
现在,我们明白Secondary NameNode所做的是在文件系统这设置一个Checkpoint来帮助NameNode更好的工作;它不是取代NameNode,也不是NameNode的备份。
Secondary NameNode的检查点进程启动,是由两个配置参数控制的:
- fs.checkpoint.period,指定连续两次检查点的最大时间间隔, 默认值是1小时。
- fs.checkpoint.size定义了edits日志文件的最大值,一旦超过这个值会导致强制执行检查点(即使没到检查点的最大时间间隔)。默认值是64MB。
如果NameNode上除了最新的检查点以外,所有的其他的历史镜像和edits文件都丢失了, NameNode可以引入这个最新的检查点。以下操作可以实现这个功能:
- 在配置参数dfs.name.dir指定的位置建立一个空文件夹;
- 把检查点目录的位置赋值给配置参数fs.checkpoint.dir;
- 启动NameNode,并加上-importCheckpoint。
NameNode会从fs.checkpoint.dir目录读取检查点,并把它保存在dfs.name.dir目录下。如果dfs.name.dir目录下有合法的镜像文件,NameNode会启动失败。 NameNode会检查fs.checkpoint.dir目录下镜像文件的一致性,但是不会去改动它。
参考地址:http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html
5.Client:(客户端)代表用户通过与nameNode和datanode交互来访问整个文件系统,HDFS对外开放文件命名空间并允许用户数据以文件形式存储。用户通过客户端(Client)与HDFS进行通讯交互。
HDFS读写流程
HDFS读文件流程:
-
客户端(client)首先调用FileSystem的open()函数打开它想要打开的文件,对于HDFS来说就是通过DistributedFileSystem实例通过RPC调用请求元数据节点,得到组成文件的前几个数据块信息。对于每一个数据块,元数据节点返回保存数据块的datanode地址(是分批次获取的,每次是几个数据块),这些datanode会按照与客户端的接近度来排序,(如果客户端节点自己就是存放了目标数据块的datanode,就优先从本节点读取)。
-
DistributedFileSystem返回FSDataInputStream(支持文件seek的输入流)给客户端,客户端就能从流中读取数据了,FSDataInputStream中封装了一个管理了datanode与namenode IO的DFSInputStream。
-
客户端调用read()方法开始读取数据,存储了文件前几个块的地址的DFSInputStream,就会链接存储了第一个块的第一个(最近的)datanode,然后DFSInputStream就通过重复调用read()方法,数据就从datanode流向了客户端,当该datanode中最后一个快的读取完成了,DFSInputStream会关闭与datanode的连接,然后为下一块寻找最佳节点。这个过程对客户端是透明的,在客户端那边就像是读取了一个连续不断的流。
-
块是顺序读取的,通过DFSInputStream在datanode上打开新的连接去作为客户端读取流,同样它也会请求namenode来获取下一批所需要的块所在的datanode地址。当客户端完成了读取就在FSDataInpuStream上调用close()方法结束整个流程。
-
在读取过程中,如果FSDataInputStream在和一个datanode进行交流时出现了一个错误,它就去试一试下一个最接近的块,同时也会记住刚才发生错误的datanode,之后便不会再在这个datanode上进行没必要的尝试。 DFSInputStream 也会在 datanode 上传输出的数据上核查检查数(checknums).如果损坏的块被发现了,DFSInputStream 就试图从另一个拥有备份的 datanode 中去读取备份块中的数据。
在这个设计中一个重要的方面是客户端直接从datanode上检索数据,并通过namenode指导来得到每一个块的最佳datanode。这种设计HDFS拓展大量的并发客户端,因为数据传输只是与集群上的所有datanode展开,namenode仅仅只需要服务于获取块位置的请求。而块位置信息是存放在内存中,所以效率很高,如果不这样设计,随着客户端数据量的增加,数据服务就会很快成为一个瓶颈。
HDFS写文件流程:
-
使用HDFS提供的客户端Client,向远程的Namenode发起RPC请求
-
Namenode会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功则会文件创建一个记录,否则会让客户端抛出异常,
-
当客户端开始写入文件的时候,客户端会将文件切分成多个packets,并在内部以数据队列“data queue"形式管理这些packets, 然后向Namenode申请blocks,获取用来存储replications的合适的datanode列表,列表的大小根据Namenode中的replication值而定。
-
开始以pipeline的形式将packet写入所有的replications中,客户端把packet以流的方式写入第一个datanode,该datanode把该packet存储之后,再将其传递给在此pipeline的下一个datanode,直到最后一个datanode,这种写数据的方式呈流水线形式。
-
最后一个datanode成功存储之后会返回一个ack packet(确认队列),在pipeline里传递给客户端,在客户端的开发库内部维护者“ack queue”,成功收到datanode返回的ack packet后会从“ack queue”移除相应的 packet。
-
如果传输过程中, 有某个datanode出现了故障, 那么当前的pipeline会被关闭, 出现故障的datanode会从当前的pipeline中移除, 剩余的block会继续剩下的datanode中继续以pipeline的形式传输, 同时Namenode会分配一个新的datanode, 保持replications设定的数量。
-
客户端完成数据的写入后,Client调用FSDataOutputStream.close()方法,关闭输出流,flush缓存 区的数据包;
-
再调用FileSystem.complete()方法,告诉Namenode节点写入成功。
HDFS中常用到的命令
1、hadoop fs
hadoop fs -ls /
hadoop fs -lsr
hadoop fs -mkdir /user/hadoop
hadoop fs -put 1.txt /user/hadoop/
hadoop fs -get /user/hadoop/1.txt /
hadoop fs -cp src dst
hadoop fs -mv src dst
hadoop fs -cat /user/hadoop/1.txt
hadoop fs -rm /user/hadoop/1.txt
hadoop fs -rmr /user/hadoop/1.txt
hadoop fs -text /user/hadoop/1.txt
hadoop fs -copyFromLocal localsrc dst 与hadoop fs -put功能类似。
hadoop fs -moveFromLocal localsrc dst 将本地文件上传到hdfs,同时删除本地文件。
YARN 的架构
- ResourceManager:主节点,主要负责接收用户提交的任务请求,进行资源分配
- NodeManager:从节点,主要负责接收和执行ApplicationMaster分配的任务
- ApplicationMaster:每提交一个任务给ResourceManager,ResourceManager就会在从节点上启动一个AppMaster,负责任务的分配和资源的申请,将任务执行情况汇报给ResourceManager等
- Container:资源分配的单位,ApplicationMaster申请到的资源都分配给一个个的container,然后再一个个的container中运行一个个maptask或者reducetask
- JobHistory:历史完成任务的界面查看
MR on YARN 执行流程
- 用户向yarn提交job,其中包含application master程序,启动application master的命令等
- RM 为该 job 分配第一个 container,与对应的 NM 通信,要求它在这个 container 启动作业的ApplicationMaster
- ApplicationMaster向 applications manager 注册,这样用户就可以通过 RM Web 查看 job 的状态
- ApplicationMaster 采用轮询的方式通过 RPC 协议向 resource scheduler 申请和领取资源
- 一旦 ApplicationMaster 申请到资源后,与对应的 NM 通信,要求启动task
- NM 为任务设置好运行环境后,将任务的启动命令写到一个脚本中,并通过该脚本启动、运行任务
- 各个任务 task 通过rpc协议汇报自己的状态和进度,以便让ApplicationMaster随时掌握各个任务的运行状态,从而在任务失败时,重启启动任务。
- job 运行完成后,ApplicationMaster 向 applications manager 注销并关闭自己