Hadoop(三)HDFS读写原理与shell命令
一 HDFS概述
1.1 HDFS产生背景
随着数据量越来越大,在一个操作系统管辖的范围内存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。
1.2 HDFS概念
HDFS,它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的设计适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
1.3 HDFS优缺点
1.3.1 优点
1)高容错性
(1)数据自动保存多个副本。它通过增加副本的形式,提高容错性。
(2)某一个副本丢失以后,它可以自动恢复。
2)适合大数据处理
(1)数据规模:能够处理数据规模达到 GB、TB、甚至PB级别的数据。
(2)文件规模:能够处理百万规模以上的文件数量,数量相当之大。
3)流式数据访问
(1)一次写入,多次读取,不能修改,只能追加。
(2)它能保证数据的一致性。
4)可构建在廉价机器上,通过多副本机制,提高可靠性。
1.3.2 缺点
1)不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。
2)无法高效的对大量小文件进行存储
(1)存储大量小文件的话,它会占用 NameNode大量的内存来存储文件、目录和块信息。这样是不可取的,因为NameNode的内存总是有限的。
(2)小文件存储的寻道时间会超过读取时间,它违反了HDFS的设计目标。
3)并发写入、文件随机修改
(1)一个文件只能有一个写,不允许多个线程同时写。
(2)仅支持数据 append(追加),不支持文件的随机修改。
抛出问题:HDFS文件系统为什么不适用于存储小文件?
这是和HDFS系统底层设计实现有关系的,HDFS本身的设计就是用来解决海量大文件数据的存储.,他天生喜欢大数据的处理,大文件存储在HDFS中,会被切分成很多的小数据块,任何一个文件不管有多小,都是一个独立的数据块,而这些数据块的信息则是保存在元数据中的,在之前的博客HDFS基础里面介绍过在HDFS集群的namenode中会存储元数据的信息,这里再说一下,元数据的信息主要包括以下3部分:
1)抽象目录树
2)文件和数据块的映射关系,一个数据块的元数据大小大约是150byte
3)数据块的多个副本存储地
而元数据的存储在磁盘(1和2)和内存中(1、2和3),而服务器中的内存是有上限的,举个例子:
有100个1M的文件存储进入HDFS系统,那么数据块的个数就是100个,元数据的大小就是100*150byte,消耗了15000byte的内存,但是只存储了100M的数据。
有1个100M的文件存储进入HDFS系统,那么数据块的个数就是1个,元数据的大小就是150byte,消耗量150byte的内存,存储量100M的数据。
所以说HDFS文件系统不适用于存储小文件。
1.4 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。
1.5 HDFS 文件块大小
HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M。
HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果块设置得足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因而,传输一个由多个块组成的文件的时间取决于磁盘传输速率。
如果寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,我们要将块大小设置约为100MB。默认的块大小128MB。
块的大小:10ms*100*100M/s = 100M
二 HDFS的辅助功能
HDFS作为一个文件系统。有两个最主要的功能:上传和下载。而为了保障这两个功能的完美和高效实现,HDFS提供了很多的辅助功能
2.1.心跳机制
1、 Hadoop 是 Master/Slave 结构,Master 中有 NameNode 和 ResourceManager,Slave 中有 Datanode 和 NodeManager
2、 Master 启动的时候会启动一个 IPC(Inter-Process Comunication,进程间通信)server 服 务,等待 slave 的链接
3、 Slave 启动时,会主动链接 master 的 ipc server 服务,并且每隔 3 秒链接一次 master,这 个间隔时间是可以调整的,参数为 dfs.heartbeat.interval,这个每隔一段时间去连接一次 的机制,我们形象的称为心跳。Slave 通过心跳汇报自己的信息给 master,master 也通 过心跳给 slave 下达命令,
4、 NameNode 通过心跳得知 Datanode 的状态 ,ResourceManager 通过心跳得知 NodeManager 的状态
5、 如果 master 长时间都没有收到 slave 的心跳,就认为该 slave 挂掉了。
最终NameNode判断一个DataNode死亡的时间计算公式:
timeout = 10 * 心跳间隔时间 + 2 * 检查一次消耗的时间
心跳间隔时间:dfs.heartbeat.interval 心跳时间:3s,检查一次消耗的时间:heartbeat.recheck.interval checktime : 5min,最终宕机之后630s后显示死亡状态。
2.2.安全模式
1、HDFS的启动和关闭都是先启动NameNode,在启动DataNode,最后在启动secondarynamenode。
2、决定HDFS集群的启动时长会有两个因素:
1)磁盘元数据的大小
2)datanode的节点个数
当元数据很大,或者 节点个数很多的时候,那么HDFS的启动,需要一段很长的时间,那么在还没有完全启动的时候HDFS能否对外提供服务?
在HDFS的启动命令start-dfs.sh执行的时候,HDFS会自动进入安全模式
为了确保用户的操作是可以高效的执行成功的,在HDFS发现自身不完整的时候,会进入安全模式。保护自己。
在正常启动之后,如果HDFS发现所有的数据都是齐全的,那么HDFS会启动的退出安全模式
3、对安全模式进行测试
安全模式常用操作命令:
hdfs dfsadmin -safemode leave //强制 NameNode 退出安全模式
hdfs dfsadmin -safemode enter //进入安全模式
hdfs dfsadmin -safemode get //查看安全模式状态
hdfs dfsadmin -safemode wait //等待,一直到安全模式结束
4、安全模式下测试上传下载,得出结论:
如果一个操作涉及到元数据的修改的话。都不能进行操作,如果一个操作仅仅只是查询。那是被允许的。所谓安全模式,仅仅只是保护namenode,而不是保护datanode。
2.3.副本存放策略
第一副本:放置在上传文件的DataNode上;如果是集群外提交,则随机挑选一台磁盘不太慢、CPU不太忙的节点上;
第二副本:放置在于第一个副本不同的机架的节点上;
第三副本:与第二个副本相同机架的不同节点上;
如果还有更多的副本:随机放在节点中;
2.4.负载均衡
负载均衡理想状态:节点均衡、机架均衡和磁盘均衡。
Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,例如:当集群内新增、删除节点,或者某个节点机器内硬盘存储达到饱和值。当数据不平衡时,Map任务可能会分配到没有存储数据的机器,这将导致网络带宽的消耗,也无法很好的进行本地计算。
当HDFS负载不均衡时,需要对HDFS进行数据的负载均衡调整,即对各节点机器上数据的存储分布进行调整。从而,让数据均匀的分布在各个DataNode上,均衡IO性能,防止热点的发生。进行数据的负载均衡调整,必须要满足如下原则:
- 数据平衡不能导致数据块减少,数据块备份丢失
- 管理员可以中止数据平衡进程
- 每次移动的数据量以及占用的网络资源,必须是可控的
- 数据均衡过程,不能影响namenode的正常工作
负载均衡的原理
数据均衡过程的核心是一个数据均衡算法,该数据均衡算法将不断迭代数据均衡逻辑,直至集群内数据均衡为止。该数据均衡算法每次迭代的逻辑如下:
步骤分析如下:
- 数据均衡服务(Rebalancing Server)首先要求 NameNode 生成 DataNode 数据分布分析报告,获取每个DataNode磁盘使用情况
- Rebalancing Server汇总需要移动的数据分布情况,计算具体数据块迁移路线图。数据块迁移路线图,确保网络内最短路径
- 开始数据块迁移任务,Proxy Source Data Node复制一块需要移动数据块
- 将复制的数据块复制到目标DataNode上
- 删除原始数据块
- 目标DataNode向Proxy Source Data Node确认该数据块迁移完成
- Proxy Source Data Node向Rebalancing Server确认本次数据块迁移完成。然后继续执行这个过程,直至集群达到数据均衡标准
DataNode分组
在第2步中,HDFS会把当前的DataNode节点,根据阈值的设定情况划分到Over、Above、Below、Under四个组中。在移动数据块的时候,Over组、Above组中的块向Below组、Under组移动。四个组定义如下:
- Over组:此组中的DataNode的均满足
DataNode_usedSpace_percent > Cluster_usedSpace_percent + threshold
- Above组:此组中的DataNode的均满足
Cluster_usedSpace_percent + threshold > DataNode_ usedSpace _percent >Cluster_usedSpace_percent
- Below组:此组中的DataNode的均满足
Cluster_usedSpace_percent > DataNode_ usedSpace_percent > Cluster_ usedSpace_percent – threshold
- Under组:此组中的DataNode的均满足
Cluster_usedSpace_percent – threshold > DataNode_usedSpace_percent
Hadoop HDFS 数据自动平衡脚本使用方法
在Hadoop中,包含一个start-balancer.sh脚本,通过运行这个工具,启动HDFS数据均衡服务。该工具可以做到热插拔,即无须重启计算机和 Hadoop 服务。HadoopHome/bin目录下的start−balancer.sh脚本就是该任务的启动脚本。启动命令为:‘HadoopHome/bin目录下的start−balancer.sh脚本就是该任务的启动脚本。启动命令为:‘Hadoop_home/bin/start-balancer.sh –threshold`
影响Balancer的几个参数:
- -threshold
- 默认设置:10,参数取值范围:0-100
- 参数含义:判断集群是否平衡的阈值。理论上,该参数设置的越小,整个集群就越平衡
- dfs.balance.bandwidthPerSec
- 默认设置:1048576(1M/S)
- 参数含义: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的读写详解
3.1 HDFS写操作
详细文字说明(术语)
1、使用 HDFS 提供的客户端 Client,向远程的 namenode 发起 RPC 请求
2、namenode 会检查要创建的文件是否已经存在,创建者是否有权限进行操作,成功则会 为文件创建一个记录,否则会让客户端抛出异常;
3、当客户端开始写入文件的时候,客户端会将文件切分成多个 packets,并在内部以数据队列“data queue(数据队列)”的形式管理这些 packets,并向 namenode 申请 blocks,获 取用来存储 replicas 的合适的 datanode 列表,列表的大小根据 namenode 中 replication 的设定而定;
4、开始以 pipeline(管道)的形式将 packet 写入所有的 replicas 中。客户端把 packet 以流的 方式写入第一个 datanode,该 datanode 把该 packet 存储之后,再将其传递给在此 pipeline 中的下一个 datanode,直到最后一个 datanode,这种写数据的方式呈流水线的形式。
5、最后一个 datanode 成功存储之后会返回一个 ack packet(确认队列),在 pipeline 里传递 至客户端,在客户端的开发库内部维护着"ack queue",成功收到 datanode 返回的 ack packet 后会从"data queue"移除相应的 packet。
6、如果传输过程中,有某个 datanode 出现了故障,那么当前的 pipeline 会被关闭,出现故 障的 datanode 会从当前的 pipeline 中移除,剩余的 block 会继续剩下的 datanode 中继续 以 pipeline 的形式传输,同时 namenode 会分配一个新的 datanode,保持 replicas 设定的 数量。
7、客户端完成数据的写入后,会对数据流调用 close()方法,关闭数据流;
8、只要写入了 dfs.replication.min(最小写入成功的副本数)的复本数(默认为 1),写操作 就会成功,并且这个块可以在集群中异步复制,直到达到其目标复本数(dfs.replication 的默认值为 3),因为 namenode 已经知道文件由哪些块组成,所以它在返回成功前只需 要等待数据块进行最小量的复制。
详细文字说明(口语)
1、客户端发起请求:hadoop fs -put hadoop.tar.gz /
客户端怎么知道请求发给那个节点的哪个进程?
因为客户端会提供一些工具来解析出来你所指定的HDFS集群的主节点是谁,以及端口号等信息,主要是通过URI来确定,
url:hdfs://hadoop1:9000
当前请求会包含一个非常重要的信息: 上传的数据的总大小
2、namenode会响应客户端的这个请求
namenode的职责:
1 管理元数据(抽象目录树结构)
用户上传的那个文件在对应的目录如果存在。那么HDFS集群应该作何处理,不会处理
用户上传的那个文件要存储的目录不存在的话,如果不存在不会创建
2、响应请求
真正的操作:做一系列的校验,
1、校验客户端的请求是否合理
2、校验客户端是否有权限进行上传
3、如果namenode返回给客户端的结果是 通过, 那就是允许上传
namenode会给客户端返回对应的所有的数据块的多个副本的存放节点列表,如:
file1_blk1 hadoop02,hadoop03,hadoop04
file1_blk2 hadoop03,hadoop04,hadoop05
4、客户端在获取到了namenode返回回来的所有数据块的多个副本的存放地的数据之后,就可以按照顺序逐一进行数据块的上传操作
5、对要上传的数据块进行逻辑切片
切片分成两个阶段:
1、规划怎么切
2、真正的切物理切片: 1 和 2
逻辑切片: 1
file1_blk1 : file1:0:128
file1_blk2 : file1:128:256
逻辑切片只是规划了怎么切
6、开始上传第一个数据块
7、客户端会做一系列准备操作
1、依次发送请求去连接对应的datnaode
pipline : client - node1 - node2 - node3
按照一个个的数据包的形式进行发送的。
每次传输完一个数据包,每个副本节点都会进行校验,依次原路给客户端
2、在客户端会启动一个服务:用户就是用来等到将来要在这个pipline数据管道上进行传输的数据包的校验信息
客户端就能知道当前从clinet到写node1,2,3三个节点上去的数据是否都写入正确和成功
8、clinet会正式的把这个快中的所有packet都写入到对应的副本节点
1、block是最大的一个单位,它是最终存储于DataNode上的数据粒度,由dfs.block.size参数决定,2.x版本默认是128M;注:这个参数由客户端配置决定;如:System.out.println(conf.get("dfs.blocksize"));//结果是134217728
2、packet是中等的一个单位,它是数据由DFSClient流向DataNode的粒度,以dfs.write.packet.size参数为参考值,默认是64K;注:这个参数为参考值,是指真正在进行数据传输时,会以它为基准进行调整,调整的原因是一个packet有特定的结构,调整的目标是这个packet的大小刚好包含结构中的所有成员,同时也保证写到DataNode后当前block的大小不超过设定值;
如:System.out.println(conf.get("dfs.write.packet.size"));//结果是65536
3、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
9、clinet进行校验,如果校验通过,表示该数据块写入成功
10、重复7 8 9 三个操作,来继续上传其他的数据块
11、客户端在意识到所有的数据块都写入成功之后,会给namenode发送一个反馈,就是告诉namenode当前客户端上传的数据已经成功。
3.2 HDFS读操作
数据读取
1、客户端调用FileSystem 实例的open 方法,获得这个文件对应的输入流InputStream。
2、通过RPC 远程调用NameNode ,获得NameNode 中此文件对应的数据块保存位置,包括这个文件的副本的保存位置( 主要是各DataNode的地址) 。
3、获得输入流之后,客户端调用read 方法读取数据。选择最近的DataNode 建立连接并读取数据。
4、如果客户端和其中一个DataNode 位于同一机器(比如MapReduce 过程中的mapper 和reducer),那么就会直接从本地读取数据。
5、到达数据块末端,关闭与这个DataNode 的连接,然后重新查找下一个数据块。
6、不断执行第2 - 5 步直到数据全部读完。
7、客户端调用close ,关闭输入流DF S InputStream。
四 HDFS命令行操作
4.1 基本语法
bin/hadoop fs 具体命令
4.2 参数大全
[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 ...]]
4.3常用命令实操
(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中文件的副本数量