HDFS 基本概念
HDFS 思想
设计思想
分而治之: 将大文件、大批量文件, 分布式存放在大量服务器上,以便于采取分而治之的方式对海量数据进行运算分析;
在大数据系统中的应用
为各类分布式运算框架(如: mapreduce, spark, tez, …) 提供数据存储服务
重点概念
文件切块, 副本存放, 元数据管理
HDFS的概念和特性
概念
首先,它是一个文件系统,用于存储文件,通过统一的命名空间——目录树来定位文件
其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色;
重要特征
DFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,老版本中是64M
HDFS文件系统会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
目录结构及文件分块信息(元数据)的管理由namenode节点承担, namenode是HDFS集群主节点,负责维护整个hdfs文件系统的目录树,以及每一个路径(文件)所对应的block块信息(block的id,及所在的datanode服务器)
文件的各个block的存储管理由datanode节点承担, datanode是HDFS集群从节点,每一个block都可以在多个datanode上存储多个副本(副本数量也可以通过参数设置dfs.replication)
HDFS是设计成适应一次写入,多次读出的场景,且不支持文件的修改, 适合用来做数据分析,并不适合用来做网盘应用,因为,不便修改,延迟大,网络开销大,成本太高
HDFS的工作机制
HDFS 工作机制介绍
- HDFS集群分为两大角色:NameNode、DataNode (Secondary Namenode)
- NameNode负责管理整个文件系统的元数据
- DataNode 负责管理用户的文件数据块
- 文件会按照固定的大小(blocksize)切成若干块后分布式存储在若干台datanode上
- 每一个文件块可以有多个副本,并存放在不同的datanode上
- Datanode会定期向Namenode汇报自身所保存的文件block信息,而namenode则会负责保持文件的副本数量
- HDFS的内部工作机制对客户端保持透明,客户端请求访问HDFS都是通过向namenode申请来进行
HDFS 写数据的流程
- 客户端与namenode通信请求上传文件,namenode检查目标文件是否已存在,父目录是否存在
- namenode返回是否可以上传
- client请求第一个 block该传输到哪些datanode服务器上
- namenode返回可以上传的节点, 示例3个datanode服务器ABC
- client请求3台dn中的一台A上传数据(本质上是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将整个pipeline建立完成,逐级返回客户端
- client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(chunk为校验单位),A收到一个packet就会传给B,B传给C;A每传一个packet会放入一个应答队列等待应答
- 当一个block传输完成之后(只要有一个节点上传成功,就算成功),client再次请求namenode上传第二个block的服务器。
HDFS读数据流程
client跟namenode通信查询元数据,找到文件块所在的datanode服务器
cilent挑选一台datanode(就近原则,然后随机)服务器,请求建立socket流
datanode开始发送数据(从磁盘里面读取数据放入流,以packet为传输单位,chunk为校验单位)
客户端以packet为单位接收,先在本地缓存,然后写入目标文件
block、packet与chunk
在DFSClient写HDFS的过程中,有三个需要搞清楚的单位:block、packet与chunk;
- block是最大的一个单位,它是最终存储于DataNode上的数据粒度,由dfs.block.size参数决定,默认是64M;注:这个参数由客户端配置决定;
- packet是中等的一个单位,它是数据由DFSClient流向DataNode的粒度,以dfs.write.packet.size参数为参考值,默认是64K;注:这个参数为参考值,是指真正在进行数据传输时,会以它为基准进行调整,调整的原因是一个packet有特定的结构,调整的目标是这个packet的大小刚好包含结构中的所有成员,同时也保证写到DataNode后当前block的大小不超过设定值;
- chunk是最小的一个单位,它是DFSClient到DataNode数据传输中进行数据校验的粒度,由io.bytes.per.checksum参数决定,默认是512B;注:事实上一个chunk还包含4B的校验值,因而chunk写入packet时是516B;数据与检验值的比值为128:1,所以对于一个128M的block会有一个1M的校验文件与之对应;
NAMENODE 工作机制
NAMENODE 的职责
负责客户端请求的响应
元数据的管理(查询,修改)
元数据管理形式
- 内存元数据(NameSystem)
- 磁盘元数据镜像文件(fsimage)
- 数据操作日志文件(edits文件, 可通过日志运算出元数据)
元数据的存储机制
- 内存中有一份完整的原数据(内存metadate)
- 磁盘中有一个”准完整”的原数据镜像(fsimage)文件(在namenode的工作目录中)
- 用于衔接metadata和持久化元数据镜像的fsimage之间的操作日志(edits文件), 当客户端对hdfs中的文件进行新增或者修改操作,操作记录会首先被记录到edits日志文件中,当客户端操作成功后,相应的原数据会更新到内存meta.data中, 并且每隔一定的间隔hdfs会将当前的metadata同步到fsimage镜像文件中
元数据手动查看
hdfs命令
1 | hdfs oev -i edits -o edits.xml |
元数据的checkpoint
由于在数据备份的时候会占用计算资源,所以为了减轻namenode的负载,通常可以将数据备份的工作交给另外一个专门用来做数据备份的namenode–> sencondary namenode
每隔一段时间,会由secondary namenode 将namenode上积累的所有edits和一个最新的fsimage下载到本地(只有第一次merge才会下载fsimage),并加载到内存进行merge(这个过程称之为checkpoint)
namenode的一些情况
namenode如果宕机,hdfs是否还能正常提供服务
不能,secondarynamenode虽然有元数据信息,但是不能更新元数据, 不能充当namenode使用
如果namenode的硬盘损坏,元数据是否能回复,能恢复多少?
可以恢复最后一次merge之前的数据, 只需要将secondarynamenode的数据目录替换成namenode的数据目录
配置namenode的工作目录时,有哪些可以注意的事项
可以将namenode的元数据保存到多块物理磁盘上例如如下的namenode配置
1 | <property> |
checkpoint 的触发条件相关配置
1 | dfs.namenode.checkpoint.check.period=60 #检查触发条件是否满足的频率,60秒 |
元数据目录说明
在第一次部署好Hadoop集群的时候,我们需要在NameNode(NN)节点上格式化磁盘:
1 | hadoop namenode -format |
元数据目录介绍
格式化完成之后,将会在$dfs.namenode.name.dir/current目录下如下的文件结构
1 | current/ |
其中的dfs.name.dir是在hdfs-site.xml文件中配置的,默认值如下:
1 | <property> |
dfs.namenode.name.dir属性可以配置多个,如/data1/dfs/name,/data2/dfs/name,/data3/dfs/name,….。
各个目录存储的文件结构和内容都完全一样,相当于备份,这样做的好处是当其中一个目录损坏了,也不会影响到Hadoop的元数据,特别是当其中一个目录是NFS(网络文件系统Network File System,NFS)之上,即使你这台机器损坏了,元数据也得到保存。
元数据目录文件介绍
VERSION文件
VERSION文件是Java属性文件,内容大致如下:
1 | Fri Nov 15 19:47:46 CST 2013 |
namespaceID是文件系统的唯一标识符,在文件系统首次格式化之后生成的;
storageType说明这个文件存储的是什么进程的数据结构信息(如果是DataNode,storageType=DATA_NODE);
cTime表示NameNode存储时间的创建时间,由于我的NameNode没有更新过,所以这里的记录值为0,以后对NameNode升级之后,cTime将会记录更新时间戳;
layoutVersion表示HDFS永久性数据结构的版本信息, 只要数据结构变更,版本号也要递减,此时的HDFS也需要升级,否则磁盘仍旧是使用旧版本的数据结构,这会导致新版本的NameNode无法使用
clusterID是系统生成或手动指定的集群ID,在-clusterid选项中可以使用它;如下说明
1
2
3
4
5使用如下命令格式化一个Namenode:选择一个唯一的cluster_id,并且这个cluster_id不能与环境中其他集群有冲突。如果没有提供cluster_id,则会自动生成一个唯一的ClusterID。
hadoop namenode -format -clusterId <cluster_id>
升级集群至最新版本。在升级过程中需要提供一个ClusterID,如果没有提供ClusterID,则会自动生成一个ClusterID。
hadoop start namenode --config $HADOOP_CONF_DIR -upgrade -clusterId <cluster_ID>blockpoolID是针对每一个Namespace所对应的blockpool的ID,上面的这个BP-893790215-192.168.24.72-1383809616115就是在我的ns1的namespace下的存储块池的ID,这个ID包括了其对应的NameNode节点的ip地址。
seen_txid文件
是存放transactionId的文件,format之后是0,它代表的是namenode里面的edits_*文件的尾数,namenode重启的时候,会按照seen_txid的数字,循序从头跑edits_0000001~到seen_txid的数字。所以当你的hdfs发生异常重启的时候,一定要比对seen_txid内的数字是不是你edits最后的尾数,不然会发生建置namenode时metaData的资料有缺少,导致误删Datanode上多余Block的资讯。
文件中记录的是edits滚动的序号,每次重启namenode时,namenode就知道要将哪些edits进行加载edits
fsimage文件和edits文件
fsimage: 元数据的镜像文件
edits: 元数据的滚动日志文件,每次merge之后会对之前的日志文件进行清除
DATANODE工作机制
DATANODE 工作职责
- 存储管理用户的文件块数据
- 定期向namenode汇报自身所持有的block信息(通过心跳上报), 当集群中的节点失效,或者block存在丢失的时候,集群可以根据汇报信息恢复block初始副本数量的问题
DATANODE 汇报间隔设置参数
1 | <property> |
DATANODE掉线判断时限参数
datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:
timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval。
.默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒
dfs配置参数
1 | <property> |
HDFS客户端操作
命令行客户端
命令格式
1 | hadoop fs -ls / |
命令行参数
1 | [-appendToFile <localsrc> ... <dst>] |
常用命令介绍
-help
功能:输出这个命令参数手册
–ls
功能:显示目录信息
示例:hadoop fs -ls hdfs://hadoop-server01:9000/
备注:这些参数中,所有的hdfs路径都可以简写, hadoop fs -ls / 等同于上一条命令的效果
-mkdir
功能:在hdfs上创建目录
示例:hadoop fs -mkdir -p /aaa/bbb/cc/dd
-moveFromLocal
功能:从本地剪切粘贴到hdfs
示例:hadoop fs - moveFromLocal /home/hadoop/a.txt /aaa/bbb/cc/dd
-moveToLocal
功能:从hdfs剪切粘贴到本地
示例:hadoop fs - moveToLocal /aaa/bbb/cc/dd /home/hadoop/a.txt*
–appendToFile
功能:追加一个文件到已经存在的文件末尾
示例:hadoop fs -appendToFile ./hello.txt hdfs://hadoop-server01:9000/hello.txt
可以简写为: hadoop fs -appendToFile ./hello.txt /hello.txt
-cat
功能:显示文件内容
示例:hadoop fs -cat /hello.txt
-tail
功能:显示一个文件的末尾
示例:hadoop fs -tail /weblog/access_log.1
-text
功能:以字符形式打印一个文件的内容
示例:hadoop fs -text /weblog/access_log.1
-chgrp , -chmod, -chown
功能:linux文件系统中的用法一样,对文件所属权限
示例:
hadoop fs -chmod 666 /hello.txt
hadoop fs -chown someuser:somegrp /hello.txt
-copyFromLocal
功能:从本地文件系统中拷贝文件到hdfs路径去
示例:hadoop fs -copyFromLocal ./jdk.tar.gz /aaa/
-copyToLocal
功能:从hdfs拷贝到本地
示例:hadoop fs -copyToLocal /aaa/jdk.tar.gz
-cp
功能:从hdfs的一个路径拷贝hdfs的另一个路径
示例:hadoop fs -cp /aaa/jdk.tar.gz /bbb/jdk.tar.gz.2
-mv
功能:在hdfs目录中移动文件
示例:hadoop fs -mv /aaa/jdk.tar.gz /
-get
功能:等同于copyToLocal,就是从hdfs下载文件到本地
示例:hadoop fs -get /aaa/jdk.tar.gz
-getmerge
功能:合并下载多个文件
示例:比如hdfs的目录 /aaa/下有多个文件:log.1, log.2,log.3,…
hadoop fs -getmerge /aaa/log.* ./log.sum
-put
功能:等同于copyFromLocal
示例:hadoop fs -put /aaa/jdk.tar.gz /bbb/jdk.tar.gz.2
-rm
功能:删除文件或文件夹
示例:hadoop fs -rm -r /aaa/bbb/
-rmdir
功能:删除空目录
示例:hadoop fs -rmdir /aaa/bbb/ccc
-df
功能:统计文件系统的可用空间信息*
示例:hadoop fs -df -h /
-du
功能:统计文件夹的大小信息
示例:hadoop fs -du -s -h /aaa/*
-count
功能:统计一个指定目录下的文件节点数量
示例:hadoop fs -count /aaa/
-setrep
功能:设置hdfs中文件的副本数量
示例:hadoop fs -setrep 3 /aaa/jdk.tar.gz
java api 使用
引入依赖(maven)
1 | <dependency> |
window 下开发需要注意
建议在linux下进行hadoop应用的开发,不会存在兼容性问题。如在window上做客户端应用开发,需要设置以下环境:
A、在windows的某个目录下解压一个hadoop的安装包
B、将安装包下的lib和bin目录用对应windows版本平台编译的本地库替换(下载地址: https://github.com/steveloughran/winutils,下载之后直接解压,将bin目录里的内容直接覆盖到hadoop的bin )
C、在window系统中配置HADOOP_HOME指向你解压的安装包
D、在windows系统的path变量中加入hadoop的bin目录
java 客户端的配置
在java中操作hdfs,首先要获得一个客户端实例
1 | Configuration conf = new Configuration() |
而我们的操作目标是HDFS,所以获取到的fs对象应该是DistributedFileSystem的实例;
get方法是从何处判断具体实例化那种客户端类呢?
—从conf中的一个参数 fs.defaultFS的配置值判断;
如果我们的代码中没有指定fs.defaultFS,并且工程classpath下也没有给定相应的配置,conf中的默认值就来自于hadoop的jar包中的core-default.xml,默认值为: file:///,则获取的将不是一个DistributedFileSystem的实例,而是一个本地文件系统的客户端对象
配置方法
1 | conf = new Configuration(); |
java 客户端 HDFS增删改查示例
1 | package com.bigdata.utils.hdfs; |
java 客户端 HDFS通过流的方式上传下载文件
1 | package com.bigdata.utils.hdfs; |
Java客户端获取文件block信息并读取指定block内容
1 |
|