随着数据量愈来愈大,在一个操做系统管辖的范围内存不下了,那么就分配到更多的操做系统管理的磁盘中,可是不方便管理和维护,迫切须要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。node
HDFS,它是一个文件系统,用于存储文件,经过目录树来定位文件;其次,它是分布式的,由不少服务器联合起来实现其功能,集群中的服务器有各自的角色。linux
HDFS的设计适合一次写入,屡次读出的场景,且不支持文件的修改。适合用来作数据分析,并不适合用来作网盘应用。算法
1.3.1 优势安全
1)高容错性服务器
(1)数据自动保存多个副本。它经过增长副本的形式,提升容错性。网络
(2)某一个副本丢失之后,它能够自动恢复。架构
2)适合大数据处理并发
(1)数据规模:可以处理数据规模达到 GB、TB、甚至PB级别的数据。app
(2)文件规模:可以处理百万规模以上的文件数量,数量至关之大。负载均衡
3)流式数据访问
(1)一次写入,屡次读取,不能修改,只能追加。
(2)它能保证数据的一致性。
4)可构建在廉价机器上,经过多副本机制,提升可靠性。
1.3.2 缺点
1)不适合低延时数据访问,好比毫秒级的存储数据,是作不到的。
2)没法高效的对大量小文件进行存储
(1)存储大量小文件的话,它会占用 NameNode大量的内存来存储文件、目录和块信息。这样是不可取的,由于NameNode的内存老是有限的。
(2)小文件存储的寻道时间会超过读取时间,它违反了HDFS的设计目标。
3)并发写入、文件随机修改
(1)一个文件只能有一个写,不容许多个线程同时写。
(2)仅支持数据 append(追加),不支持文件的随机修改。
这是和HDFS系统底层设计实现有关系的,HDFS自己的设计就是用来解决海量大文件数据的存储.,他天生喜欢大数据的处理,大文件存储在HDFS中,会被切分红不少的小数据块,任何一个文件无论有多小,都是一个独立的数据块,而这些数据块的信息则是保存在元数据中的,在以前的博客HDFS基础里面介绍过在HDFS集群的namenode中会存储元数据的信息,这里再说一下,元数据的信息主要包括如下3部分:
1)抽象目录树
2)文件和数据块的映射关系,一个数据块的元数据大小大约是150byte
3)数据块的多个副本存储地
而元数据的存储在磁盘(1和2)和内存中(一、2和3),而服务器中的内存是有上限的,举个例子:
有100个1M的文件存储进入HDFS系统,那么数据块的个数就是100个,元数据的大小就是100*150byte,消耗了15000byte的内存,可是只存储了100M的数据。
有1个100M的文件存储进入HDFS系统,那么数据块的个数就是1个,元数据的大小就是150byte,消耗量150byte的内存,存储量100M的数据。
因此说HDFS文件系统不适用于存储小文件。
1)Client:就是客户端。
(1)文件切分。文件上传 HDFS 的时候,Client 将文件切分红一个一个的Block,而后进行存储。
(2)与NameNode交互,获取文件的位置信息。
(3)与DataNode交互,读取或者写入数据。
(4)Client提供一些命令来管理HDFS,好比启动或者关闭HDFS。
(5)Client能够经过一些命令来访问HDFS。
2)NameNode:就是master,它是一个主管、管理者。
(1)管理HDFS的名称空间。
(2)管理数据块(Block)映射信息
(3)配置副本策略
(4)处理客户端读写请求。
3) DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操做。
(1)存储实际的数据块。
(2)执行数据块的读/写操做。
4) Secondary NameNode:并不是NameNode的热备。当NameNode挂掉的时候,它并不能立刻替换NameNode并提供服务。
(1)辅助NameNode,分担其工做量。
(2)按期合并Fsimage和Edits,并推送给NameNode。
(3)在紧急状况下,可辅助恢复NameNode。
HDFS中的文件在物理上是分块存储(block),块的大小能够经过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M。
HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。若是块设置得足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。于是,传输一个由多个块组成的文件的时间取决于磁盘传输速率。
若是寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,咱们要将块大小设置约为100MB。默认的块大小128MB。
块的大小:10ms*100*100M/s = 100M
HDFS做为一个文件系统。有两个最主要的功能:上传和下载。而为了保障这两个功能的完美和高效实现,HDFS提供了不少的辅助功能
一、 Hadoop 是 Master/Slave 结构,Master 中有 NameNode 和 ResourceManager,Slave 中有 Datanode 和 NodeManager
二、 Master 启动的时候会启动一个 IPC(Inter-Process Comunication,进程间通讯)server 服 务,等待 slave 的连接
三、 Slave 启动时,会主动连接 master 的 ipc server 服务,而且每隔 3 秒连接一次 master,这 个间隔时间是能够调整的,参数为 dfs.heartbeat.interval,这个每隔一段时间去链接一次 的机制,咱们形象的称为心跳。Slave 经过心跳汇报本身的信息给 master,master 也通 过心跳给 slave 下达命令,
四、 NameNode 经过心跳得知 Datanode 的状态 ,ResourceManager 经过心跳得知 NodeManager 的状态
五、 若是 master 长时间都没有收到 slave 的心跳,就认为该 slave 挂掉了。
最终NameNode判断一个DataNode死亡的时间计算公式:
timeout = 10 * 心跳间隔时间 + 2 * 检查一次消耗的时间
心跳间隔时间:dfs.heartbeat.interval 心跳时间:3s,检查一次消耗的时间:heartbeat.recheck.interval checktime : 5min,最终宕机以后630s后显示死亡状态。
一、HDFS的启动和关闭都是先启动NameNode,在启动DataNode,最后在启动secondarynamenode。
二、决定HDFS集群的启动时长会有两个因素:
1)磁盘元数据的大小
2)datanode的节点个数
当元数据很大,或者 节点个数不少的时候,那么HDFS的启动,须要一段很长的时间,那么在尚未彻底启动的时候HDFS可否对外提供服务?
在HDFS的启动命令start-dfs.sh执行的时候,HDFS会自动进入安全模式
为了确保用户的操做是能够高效的执行成功的,在HDFS发现自身不完整的时候,会进入安全模式。保护本身。
在正常启动以后,若是HDFS发现全部的数据都是齐全的,那么HDFS会启动的退出安全模式
三、对安全模式进行测试
安全模式经常使用操做命令:
hdfs dfsadmin -safemode leave //强制 NameNode 退出安全模式
hdfs dfsadmin -safemode enter //进入安全模式 hdfs dfsadmin -safemode get //查看安全模式状态 hdfs dfsadmin -safemode wait //等待,一直到安全模式结束
四、安全模式下测试上传下载,得出结论:
若是一个操做涉及到元数据的修改的话。都不能进行操做,若是一个操做仅仅只是查询。那是被容许的。所谓安全模式,仅仅只是保护namenode,而不是保护datanode。
第一副本:放置在上传文件的DataNode上;若是是集群外提交,则随机挑选一台磁盘不太慢、CPU不太忙的节点上;
第二副本:放置在于第一个副本不一样的机架的节点上;
第三副本:与第二个副本相同机架的不一样节点上;
若是还有更多的副本:随机放在节点中;
负载均衡理想状态:节点均衡、机架均衡和磁盘均衡。
Hadoop的HDFS集群很是容易出现机器与机器之间磁盘利用率不平衡的状况,例如:当集群内新增、删除节点,或者某个节点机器内硬盘存储达到饱和值。当数据不平衡时,Map任务可能会分配到没有存储数据的机器,这将致使网络带宽的消耗,也没法很好的进行本地计算。
当HDFS负载不均衡时,须要对HDFS进行数据的负载均衡调整,即对各节点机器上数据的存储分布进行调整。从而,让数据均匀的分布在各个DataNode上,均衡IO性能,防止热点的发生。进行数据的负载均衡调整,必需要知足以下原则:
数据均衡过程的核心是一个数据均衡算法,该数据均衡算法将不断迭代数据均衡逻辑,直至集群内数据均衡为止。该数据均衡算法每次迭代的逻辑以下:
步骤分析以下:
在第2步中,HDFS会把当前的DataNode节点,根据阈值的设定状况划分到Over、Above、Below、Under四个组中。在移动数据块的时候,Over组、Above组中的块向Below组、Under组移动。四个组定义以下:
DataNode_usedSpace_percent > Cluster_usedSpace_percent + threshold
Cluster_usedSpace_percent + threshold > DataNode_ usedSpace _percent >Cluster_usedSpace_percent
Cluster_usedSpace_percent > DataNode_ usedSpace_percent > Cluster_ usedSpace_percent – threshold
Cluster_usedSpace_percent – threshold > DataNode_usedSpace_percent
在Hadoop中,包含一个start-balancer.sh脚本,经过运行这个工具,启动HDFS数据均衡服务。该工具能够作到热插拔,即无须重启计算机和 Hadoop 服务。HadoopHome/bin目录下的start−balancer.sh脚本就是该任务的启动脚本。启动命令为:‘HadoopHome/bin目录下的start−balancer.sh脚本就是该任务的启动脚本。启动命令为:‘Hadoop_home/bin/start-balancer.sh –threshold`
影响Balancer的几个参数:
示例以下:
#启动数据均衡,默认阈值为 10% $Hadoop_home/bin/start-balancer.sh #启动数据均衡,阈值 5% bin/start-balancer.sh –threshold 5 #中止数据均衡 $Hadoop_home/bin/stop-balancer.sh
在hdfs-site.xml文件中能够设置数据均衡占用的网络带宽限制
<property> <name>dfs.balance.bandwidthPerSec</name> <value>1048576</value> <description> Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second. </description> </property>
一、使用 HDFS 提供的客户端 Client,向远程的 namenode 发起 RPC 请求
二、namenode 会检查要建立的文件是否已经存在,建立者是否有权限进行操做,成功则会 为文件建立一个记录,不然会让客户端抛出异常;
三、当客户端开始写入文件的时候,客户端会将文件切分红多个 packets,并在内部以数据队列“data queue(数据队列)”的形式管理这些 packets,并向 namenode 申请 blocks,获 取用来存储 replicas 的合适的 datanode 列表,列表的大小根据 namenode 中 replication 的设定而定;
四、开始以 pipeline(管道)的形式将 packet 写入全部的 replicas 中。客户端把 packet 以流的 方式写入第一个 datanode,该 datanode 把该 packet 存储以后,再将其传递给在此 pipeline 中的下一个 datanode,直到最后一个 datanode,这种写数据的方式呈流水线的形式。
五、最后一个 datanode 成功存储以后会返回一个 ack packet(确认队列),在 pipeline 里传递 至客户端,在客户端的开发库内部维护着"ack queue",成功收到 datanode 返回的 ack packet 后会从"data queue"移除相应的 packet。
六、若是传输过程当中,有某个 datanode 出现了故障,那么当前的 pipeline 会被关闭,出现故 障的 datanode 会从当前的 pipeline 中移除,剩余的 block 会继续剩下的 datanode 中继续 以 pipeline 的形式传输,同时 namenode 会分配一个新的 datanode,保持 replicas 设定的 数量。
七、客户端完成数据的写入后,会对数据流调用 close()方法,关闭数据流;
八、只要写入了 dfs.replication.min(最小写入成功的副本数)的复本数(默认为 1),写操做 就会成功,而且这个块能够在集群中异步复制,直到达到其目标复本数(dfs.replication 的默认值为 3),由于 namenode 已经知道文件由哪些块组成,因此它在返回成功前只需 要等待数据块进行最小量的复制。
一、客户端发起请求:hadoop fs -put hadoop.tar.gz /
客户端怎么知道请求发给那个节点的哪一个进程?
由于客户端会提供一些工具来解析出来你所指定的HDFS集群的主节点是谁,以及端口号等信息,主要是经过URI来肯定,
url:hdfs://hadoop1:9000
当前请求会包含一个很是重要的信息: 上传的数据的总大小
二、namenode会响应客户端的这个请求
namenode的职责:
1 管理元数据(抽象目录树结构)
用户上传的那个文件在对应的目录若是存在。那么HDFS集群应该做何处理,不会处理
用户上传的那个文件要存储的目录不存在的话,若是不存在不会建立
二、响应请求
真正的操做:作一系列的校验,
一、校验客户端的请求是否合理
二、校验客户端是否有权限进行上传
三、若是namenode返回给客户端的结果是 经过, 那就是容许上传
namenode会给客户端返回对应的全部的数据块的多个副本的存放节点列表,如:
file1_blk1 hadoop02,hadoop03,hadoop04
file1_blk2 hadoop03,hadoop04,hadoop05
四、客户端在获取到了namenode返回回来的全部数据块的多个副本的存放地的数据以后,就能够按照顺序逐一进行数据块的上传操做
五、对要上传的数据块进行逻辑切片
切片分红两个阶段:
一、规划怎么切
二、真正的切物理切片: 1 和 2
逻辑切片: 1
file1_blk1 : file1:0:128
file1_blk2 : file1:128:256
逻辑切片只是规划了怎么切
六、开始上传第一个数据块
七、客户端会作一系列准备操做
一、依次发送请求去链接对应的datnaode
pipline : client - node1 - node2 - node3
按照一个个的数据包的形式进行发送的。
每次传输完一个数据包,每一个副本节点都会进行校验,依次原路给客户端
二、在客户端会启动一个服务:用户就是用来等到未来要在这个pipline数据管道上进行传输的数据包的校验信息
客户端就能知道当前从clinet到写node1,2,3三个节点上去的数据是否都写入正确和成功
八、clinet会正式的把这个快中的全部packet都写入到对应的副本节点
一、block是最大的一个单位,它是最终存储于DataNode上的数据粒度,由dfs.block.size参数决定,2.x版本默认是128M;注:这个参数由客户端配置决定;如:System.out.println(conf.get("dfs.blocksize"));//结果是134217728
二、packet是中等的一个单位,它是数据由DFSClient流向DataNode的粒度,以dfs.write.packet.size参数为参考值,默认是64K;注:这个参数为参考值,是指真正在进行数据传输时,会以它为基准进行调整,调整的缘由是一个packet有特定的结构,调整的目标是这个packet的大小恰好包含结构中的全部成员,同时也保证写到DataNode后当前block的大小不超过设定值;
如:System.out.println(conf.get("dfs.write.packet.size"));//结果是65536
三、chunk是最小的一个单位,它是DFSClient到DataNode数据传输中进行数据校验的粒度,由io.bytes.per.checksum参数决定,默认是512B;注:事实上一个chunk还包含4B的校验值,于是chunk写入packet时是516B;数据与检验值的比值为128:1,因此对于一个128M的block会有一个1M的校验文件与之对应;
如:System.out.println(conf.get("io.bytes.per.checksum"));//结果是512
九、clinet进行校验,若是校验经过,表示该数据块写入成功
十、重复7 8 9 三个操做,来继续上传其余的数据块
十一、客户端在乎识到全部的数据块都写入成功以后,会给namenode发送一个反馈,就是告诉namenode当前客户端上传的数据已经成功。
一、客户端调用FileSystem 实例的open 方法,得到这个文件对应的输入流InputStream。
二、经过RPC 远程调用NameNode ,得到NameNode 中此文件对应的数据块保存位置,包括这个文件的副本的保存位置( 主要是各DataNode的地址) 。
三、得到输入流以后,客户端调用read 方法读取数据。选择最近的DataNode 创建链接并读取数据。
四、若是客户端和其中一个DataNode 位于同一机器(好比MapReduce 过程当中的mapper 和reducer),那么就会直接从本地读取数据。
五、到达数据块末端,关闭与这个DataNode 的链接,而后从新查找下一个数据块。
六、不断执行第2 - 5 步直到数据所有读完。
七、客户端调用close ,关闭输入流DF S InputStream。
bin/hadoop fs 具体命令
[root@node21 hadoop-2.7.6]$ bin/hadoop fs
[-appendToFile <localsrc> ... <dst>] [-cat [-ignoreCrc] <src> ...] [-checksum <src> ...] [-chgrp [-R] GROUP PATH...] [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...] [-chown [-R] [OWNER][:[GROUP]] PATH...] [-copyFromLocal [-f] [-p] <localsrc> ... <dst>] [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>] [-count [-q] <path> ...] [-cp [-f] [-p] <src> ... <dst>] [-createSnapshot <snapshotDir> [<snapshotName>]] [-deleteSnapshot <snapshotDir> <snapshotName>] [-df [-h] [<path> ...]] [-du [-s] [-h] <path> ...] [-expunge] [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>] [-getfacl [-R] <path>] [-getmerge [-nl] <src> <localdst>] [-help [cmd ...]] [-ls [-d] [-h] [-R] [<path> ...]] [-mkdir [-p] <path> ...] [-moveFromLocal <localsrc> ... <dst>] [-moveToLocal <src> <localdst>] [-mv <src> ... <dst>] [-put [-f] [-p] <localsrc> ... <dst>] [-renameSnapshot <snapshotDir> <oldName> <newName>] [-rm [-f] [-r|-R] [-skipTrash] <src> ...] [-rmdir [--ignore-fail-on-non-empty] <dir> ...] [-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]] [-setrep [-R] [-w] <rep> <path> ...] [-stat [format] <path> ...] [-tail [-f] <file>] [-test -[defsz] <path>] [-text [-ignoreCrc] <src> ...] [-touchz <path> ...] [-usage [cmd ...]]
(1)-help:输出这个命令参数(2)-ls: 显示目录信息(3)-mkdir:在hdfs上建立目录(4)-moveFromLocal从本地剪切粘贴到hdfs(5)-appendToFile :追加一个文件到已经存在的文件末尾(6)-cat :显示文件内容(7)-tail:显示一个文件的末尾(8)-chgrp 、-chmod、-chown:linux文件系统中的用法同样,修改文件所属权限(9)-copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去(10)-copyToLocal:从hdfs拷贝到本地t(11)-cp :从hdfs的一个路径拷贝到hdfs的另外一个路径(12)-mv:在hdfs目录中移动文件(13)-get:等同于copyToLocal,就是从hdfs下载文件到本地(14)-getmerge :合并下载多个文件,好比hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,...(15)-put:等同于copyFromLocal(16)-rm:删除文件或文件夹(17)-rmdir:删除空目录(18)-df :统计文件系统的可用空间信息(19)-du统计文件夹的大小信息(20)-setrep:设置hdfs中文件的副本数量