HDFS概述,读写原理及shell命令
一.HDSF概述
1.产生背景
当今世界正处在大数据的时代,随着数据量越来越大,使用单个操作系统的存储方式显然不能满足大数据存储的需求,因此,需要一种系统来存储大数据时代产生的海量数据,于是分布式文件系统(Distributed File System ,DFS)就诞生了。
分布式文件系统是指文件系统管理的物理资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。它允许将一个文件通过网络在多台主机上以多副本的方式进行存储,实际上是通过网络来访问文件,,而用户和程序员好像是访问本地的文件系统一样。
HDFS(Hadoop Distributed File Syste)即是hadoop中的分布式文件系统,用于大数据领域的数据存储。
2.HDFS的优缺点
(1)HDSF的优点
1)支持处理超大文件
- 数据规模:能够处理数据规模达到 GB、TB、甚至PB级别的数据。
- 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
2)运行在廉价的机器上
- 由于副本机制,可以在廉价机器上使用
3)高容错性
- 数据自动保存多个副本,通过增加副本的形式,提高容错性,一个副本丢失后,它可以自动恢复
4)流式文件写入
- HDFS提供一次写入,多次提取的服务。文件一旦写入,就不能修改,只能增加,可以提高I/O性能,保证数据的一致性。
(2)HDFS的缺点
1)不适合低延迟数据访问的场景。
- 比如毫秒级的存储数据,是做不到的。
2)不适合大量小文件的存储。
- HDFS中的元数据(如目录结构,文件目录属性,文件Block的节点列表等)存储在NameNode中,整个文件系统的文件数量会受限于NameNode的内存大小。一旦集群中的小文件过多,会导致NameNode的压力倍增,进而影响集群的性能。一般采用SequenceFile等方式对小文件进行合并,或者是使用NameNode Federation 的方式来改善
3)不适合并发写入,文件随机修改场景
- HDFS采用追加(append-only)的方式写入数据,不支持在文件的任意位置修改。
3.HDFS设计目标
(1)硬件故障
故障检测和自动快速恢复是HDFS最核心的架构设计目标
(2)大规模数据集
HDFS文件大小一般在GB至TB量级,HDFS应该提供很高的聚合数据带宽,能在一个集群里扩展到数百个节点
(3)移动计算比移动数据更经济
在靠近计算的数据存储的位置进行计算是最理想状态,可以消除网络拥堵,提高系统的整体的吞吐量。HDFS为应用提供了将计算移动到数据附近的接口
二.HDFS架构
采用的是master/slave架构设计
注:
- metadata:元数据—描述数据的数据,对数据及信息资源的描述性信息
- ops:操作
- rack:机架,多台机器会放在一个机架上
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)启动DataNode进程时向NameNode汇报块信息
(3)通过向NameNode发送心跳保持联系,如果NameNode在10分钟内没有收到DataNode的心跳,则认为该DataNode已经丢失,NameNode会将该DataNode的块复制到其他DataNode上
(4)执行块数据的读/写操作
4.Secondary NameNode:从数据节点
并非NameNode的备用节点
主要功能:
周期性的将EditLog文件中对HDFS的操作合并到一个FsImage文件中,然后清空EditLog文件,防止日志文件过大。合并后的FsImage文件在元数据节点保存一份,NameNode重启就会加载最新的FsImage文件,这样就可以减少HDFS重启的时间。
即Secondary NameNode是用来帮助NameNode将内存中的元数据信息持久化到硬盘上。
三.使用HDFS处理移动通信数据
使用HDSF shell和 Java API实现HDFS管理移动数据文件
1.使用HDFS shell 完成移动通信业务数据管理操作
基本语法:/bin/hdfs dfs -cmd<args>
1)创建存放数据文件的目录
hdfs dfs -mkdir -p /hdfs/shell
hdfs dfs -ls /hdfs/shell
2)将通讯数据上传到HDFS并查看
hdfs dfs -put|copyFromLocal|moveFromLocal /home/hadoop/data/mobile.txt /hdfs/shell
hdfs dfs -text /hdfs/shell/mobile.txt
3)下载文件到本地
hdfs dfs -get|copyToLocal|moveToLocal /hdfs/shell/mobile.txt /home/hadoop
4)统计目录下文件大小
hdfs dfs -du /hdfs/shell
5)删除移动数据文件和目录
hdfs dfs -rm -rf /hdfs/shell/mobile.txt
hdfs dfs -rmr /hdfs
2.使用Java API操作完成移动通信数据的管理
1)在Idea中创建maven项目:如何创建见博客:maven项目创建
2)添加Maven依赖包,即Maven pom文件(注意依赖包的版本要与实际环境安装的版本相同)
3)使用Java API操作HDFS
以上具体内容参考博客:Java API操作完成移动通信数据的管理
4)报错异常:
【!】如果报权限异常的错误:
修改方式
a)在获取文件系统时加上root权限
FileSystem fs=FileSystem.get(new URI("hdfs://192.168.36.32:9000") ,conf,"root");
b)或者之间修改根目录下所有文件的所有权限
hdfs dfs -chmod -R 777 /hdfs
【!!】如果出现空指针异常,在无法上传是,需要配置一下hadoop在windows的文件变量
具体操作在以上博客第一条window安装hadoop即配置即可
四.HDFS读写运行原理
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.客户端发起请求: hdfs dfs -put /hdfs/shell
客户端怎么知道请求发送给哪一个节点的哪一个进程?
答:因为客户端会提供一些工具来解析出你所之指定的HDFS集群的主节点是谁,以及端口号信息,主要通过URI来确定
url:hdfs://hadoop1:9000
在配置文件core-site.xml有进行namenode的主机名和端口号配置,客户端可以通过获取主节点信息进行请求
<!-- 配置NameNode的主机名和端口号-->
<property>
<name>fs.defaultFS</name>
<value>hdfs://192.168.36.33:9000</value>
</property>
2.NameNode会响应客户端的这个请求
(1)管理元数据(抽象目录树结构)
用户上传的那个文件在对应的目录如果存在。那么HDFS集群应该作何处理,不会处理
用户上传的那个文件要存储的目录不存在的话,如果不存在不会创建,会抛异常
(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)依次发送请求去连接对应的datanode
pipline : client - node1 - node2 - node3
按照一个个的数据包的形式进行发送的。
每次传输完一个数据包,每个副本节点都会进行校验,依次原路给客户端
(2)在客户端会启动一个服务:
用户就是用来等到将来要在这个pipline数据管道上进行传输的数据包的校验信息
客户端就能知道当前从client到写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.client进行校验,如果校验通过,表示该数据块写入成功
10.重复7 8 9 三个操作,来继续上传其他的数据块
11.客户端在意识到所有的数据块都写入成功之后,会给namenode发送一个反馈,就是告诉namenode当前客户端上传的数据已经成功。
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 ,关闭输入流DFS InputStream。
此博客参考于:https://www.cnblogs.com/frankdeng/p/9133394.html
注:
关于HDFS的其他辅助功能,文件格式,以及Java 高级API操作,之后博客进行更新