学习摘要:
学习阶段,有不对的地方请指出,不胜感激。
/**
HDFS:分布式文件系统,主要是用来解决海量数据的存储问题;
思想:分而治之。
应用:为其他分布式计算框架提供数据存储服务;
重点概念:数据块/副本、负载均衡、心跳机制、副本存放策略、元数据/元数据管理、安全模式、机架感知等等。
HDFS的设计思路:
1、大文件被切割成小文件,使用分而治之的思想让很多服务器对同一个文件进行联合管理。
2、每个小文件做冗余备份,并且分散存储到不同的服务器,做到高可靠不丢失。
HDFS的架构:
主节点NameNode:是集群的管理者,掌管文件系统目录树,处理客户端读写请求。
SecondaryNameNode:定期合并NameNode中fsimage和edits文件形成新的fsiamge文件跟新NameNode中的fsimage文件
从节点DataNode:存储整个集群所有的数据块,处理真正数据读写。
文件系统存储文件通过统一的命名空间--目录树来定位文件。
1、HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数(dfs.blocksize)来设置,默认的2.x版本中是128M;
2、HDFS文件系统会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件
eg:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data
3、目录结构及文件分块位置信息(元数据)的管理由NameNode节点承担
namenode是HDFS集群主节点,负责维护整个hdfs文件系统的目录树,以及每一个路径(文件)所对应的block块信息
4、文件的各个block的存储管理有datanode节点来承担;
5、HDFS是设计适应一次写入,多次读取的场景,不支持文件的修改,但是允许文件内容的追加;
适合用来做数据分析,并不适合用来做网盘应用,因为:不便修改,延迟大,网络开销大,成本高;
HDFS优点:
1、可构建在廉价的机器上,创建多个副本提高可靠性,提供容错和回复机制;
2、高容错性,数据自动保存多个副本,副本丢失后,自动恢复;
3、适合做批处理,移动计算而非移动数据,数据位置暴露给计算框架
4、适合大数据处理,百万规模以上的文件数量,10K+节点规模;
5、流式文件访问,一次性写入,多次读取,保证数据一致性。
HDFS缺点:
1、不适合低延迟数据访问,比如毫秒级。
2、不适合小文件存取,一个小文件占用一个block块,不同文件的block块没有关联,这样就会产生大量的block块,
每个block块的信息都要存储在NameNode的内存中,这样会占用很多的内存,
小文件过多,也会浪费大量的寻址时间;
3、不适合并发写入,文件随机修改,一个文件只能有一个写者,仅仅支持append操作;
HDFS不适合存储小文件的原因:
元数据信息存储在NameNode内存中,一个节点的内存是有限的;
存取大量小文件消耗大量的寻道时间
hdfs常用的命令:
hadoop fs -ls /
hadoop fs -put /dd /aa
hadoop fs -get /aa /bb
hadoop fs -mkdir -p /ddd/eee
hadoop fs -rm -r /ddd/eee
hadoop fs -getmerge /aaa/log.* ./log.sum
hadoop fs cp /aaa /bbb
hadoop fs mv /aaa /bbb
hadoop fs -rmdir /aaa/bbb
hadoop fs -appendToFile /hello.txt /helloWorld.txt
hadoop fs cat /hello.txt
hadoop fs tail /hello.txt
hadoop fs -text /hello.txt 以字符形式
hadoop fs -chgrp
hadoop fs -chmod 666 /hello.txt
hadoop fs -chown someUser:someGroup /hello.txt
hadoop fs -df -h /
hadoop fs -du -s -h /aaa/*
hadoop fs -count /aaa/ 统计一个指定目录下的文件节点数量
hadoop fs -setrep 3 /aaa/hello.txt 设置某个文件的副本数量
hdfs dfsadmin -report 查看dfs集群工作状态的命令。
JAVA API操作:
创建文件,导入包:common hdfs
关键步骤:
创建文件系统对象:FileSystem fs = FileSystem.get(conf)
根据上面命令需求创建:Configuration conf = new Configuration();
如果我们在集群上跑:conf.set("fs.defaultFS","hdfs://hadoop01:9000");
设置文件系统搭建使用的用户:Sytem.setProperty("HADOOP_USER_NAME","hadoop");
参数优先级: 1、客户端代码中设置的值 2、classpath下的用户自定义配置文件 3、然后是服务器的默认配置
conf.set("dfs.replication", "2");
conf.set("dfs.block.size", "128m");
构造一个配置参数对象,设置一个参数:我们要访问的hdfs的URI
从而FileSystem.get()方法就知道应该是去构造一个访问hdfs文件系统的客户端,以及hdfs的访问地址 new
Configuration();的时候,它就会去加载jar包中的hdfs-default.xml
然后再加载classpath下的hdfs-site.xml
conf.addResource("config/core-site.xml");
conf.addResource("config/hdfs-site.xml");
conf.addResource("config/mapred-site.xml");
conf.addResource("config/yarn-site.xml");
常用的操作:
1、创建文件夹:fs.mkdirs(new Path("")) 这里可以直接创建多级目录;
2、上传文件:fs.copyFromLocalFile("源文件地址","目标地址")
3、下载文件:fs.copyToLocalFile(new Path("/wordcount/input/helloWorld.txt"), new Path("c:/"));
4、重命名一个文件:fs.rename(new Path("/hadoop-eclipse-plugin-2.6.4.jar"), new Path("/eclipsePlugin.jar"));
5、判断路径是否存在:fs.exists(new Path(""));
6、迭代删除文件:fs.delete(new Path(""),true);
7、获取一个路径下的所有的文件和文件夹列表,不包括子文件下的内容!!!
FileStatus[] listStatus = fs.listStatus(new Path("/wordcount"));
判断一个资源是文件还是文件夹:[文件夹]fileStatus.isDirectory() [文件]fileStatus.isFile()
8、获取一个指定路径下的所有的文件
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/wordcount"), true);
获取文件的block块的信息:
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
下载HDFS文件:
首先open一个针对HDFS上的输入流:open一个针对HDFS上文件的输入流:
FSDataInputStream in = fs.open(new Path("/jdk-7u65-linux-i586.tar.gz"));
再构造一个文件的输出流----针对本地的
FileOutputStream out = new FileOutputStream(new File("下载到哪里"));
IOUtils.copyBytes(in,out,4096);
上传一个文件到HDFS上:
首先创建一个输入流----针对本地要上传的文件
FileInputStream in = new FileInputStream("本地要上传的文件的路径");
再创建一个输出流----针对本地的文件;
FSDataOutputStream out = fs.create(new Path("文件要存储到hdfs的路径"));
IOUtils.copyBytes(in,out,4096);
随机读取:FSDataInputStream in = fs.open(new Path("/someThing.txt"));
in.seek(10);
FileOutputSteam out = new FilePOutputStream(new File("dddddd"));
IOUtils.copyBytes(in,out,19L,true); 19L就是指的读取的长度。
HDFS的核心设计:
一、hadoop的心跳机制:
1、hadoop是Master/Slave结构,Master中有Namenode和ResourceManager, Slave中有DataNode和NodeManager;
2、Mater启动的时候会启动一个IPC(进程间通信)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掉线死亡的时长计算:
HDFS默认的超时时间为10分钟+30秒
timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval
heartbeat.recheck.interval单位为毫秒30000 默认5分钟;
dfs.heartbeat.interval单位是秒3 默认的是3秒
<property>
<name>heartbeat.recheck.interval</name>
<value>5000</value>
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value>
</property>
二、HDFS安全模式
safemode是namenode的一种状态;
NameNode进入安全模式的原理:
a、namenode发现集群中的block丢失率达到一定比例时(0.1%),namenode就会进入安全模式,
在安全模式下,客户端不能对任何数据进行操作,只能查看元数据信息(比如:ls/mkdir)
这个丢失率是可以手动配置的,默认是:dfs.safemode.threshold.pct=0.999f
b、如何退出安全模式:
1、找到问题所在,进行修复(比如修复宕机的datanode)
2、或者可以进行手动的强行退出安全模式(但是这样并没有真正的解决问题)
hdfs dfsadmin -safemode leave 手动离开安全模式
hdfs dfsadmin -safemode get 查看安全模式的状态
在hdfs集群正常的冷启动的时候,NameNode也会在safemode状态下维持相当长的一段时间,此时你不需要去理会,会自动退出;
正常启动进入安全模式的原理:
namenode的内存元数据中,包含文件路径、副本数、blockId,以及每一block所在datanode的信息,而fsimage中,不包含block所在的
datanode信息----->就会导致namenode认为所有的block都已经丢失----->进入安全模式----->datanode启动之后,会定期向namenode汇报
自身所持有的blockId信息-----随着datanode陆续启动,从而陆续汇报block信息,namenode就会将内存元数据中的bolck所在的datanode
信息补全更新----->找到了所有block的位置,从而会自动的退出安全模式。
三、副本存放策略
1、作用:
数据分块存储和副本的存放,是保证可靠性和高性能的关键;
2、方法:
将每个文件的数据进行分块存储,每一个数据块又保存有多个副本,这些数据块副本分布在不同的机器节点上。
3、存放说明:
在多数情况下,HDFS默认的副本系数是3
第一个副本:存放在和client所在的节点里(如果client不在集群范围中,则第一个node随机选取的,
系统会尝试不选择哪些不满或者太忙的node);
第二个副本:放置在与第一个节点不同的机架中的节点中;
第三个副本:和第二个在同一机架,随机放在不同的节点中。
4、修改副本数:
修改hdfs-site.xml文件:
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
命令设置:hadoop fs -setrep -R 2 /
四、负载均衡
机器和机器之间的磁盘利用率不平衡是HDFS集群中一个非常容易出现的一个情况;
尤其在datanode节点出现故障或者在现有的集群上增添新的datanode的时候,
分析数据块分布和重新均衡datanode上的数据分布的方法:
start-balancer.sh
start-balancer.sh -threshold 5
自动进行均衡非常慢,一天能移动的数据量在10G-10T的级别,很难满足超大集群的需求
原因:HDFS集群默认不允许balance操作,占用很大的网络带宽,这个带宽是可以调整的
hdfs dfsadmin -setBalanacerBandwidth 10485760
该数值的单位是字节,上面的配置是10M/s 默认的是1M/s
另外可以在hdfs-site.xml配置文件中配置修改:
<property>
<name>dfs.balance.bandwidthPerSec</name>
<value>10485760</value>
</property>
start-balancer.sh -t 10%
机器容量最高的那个值 和 最低的那个值之间的差距 不能超过10%
五大常用的命令:
tar -zxvf hadoop.tart.gz -C apps/
rm -rf / 这个命令谨慎使用
tail -f
netstat -nltp 查看进程号和端口号的对应关系
ps -ef / ps -aux 查看进程详情
rpm -ivh / yum install -y 安装一个软件 只适用于centos
两大常见的异常:
command not found 要么命令写错 要么path变量中根本就没有这个命令
no such file or direcotory
元数据:
1、抽象目录树结构
2、系统中的每一个文件和它的切块之间的映射关系
3、每一个切块都有多个副本,这些副本的存放地
那么集群在经过一段时间的使用之后,就有可能给客户端提供错误的数据 为什么?
因为HDFS集群中的任何一个datanode都是不可靠的。也就意味着datanode会宕机
如果有一个datnaode宕机
那么该datnaode上的所有数据块副本都会被HDFS的自我恢复机制在其他的datanode中复制出来
以前的一个数据块的三个副本存放地 就会有一个 host 发生变化
2 3 4 ----> 4 宕机 ----> 自我恢复 -- 2 3 5
那就要求datanode每隔一段固定的时间,都需要向namenode进行汇报
按照规定,每个datanode都是需要向namenode进行汇报。
那么如果从某个时刻开始,某个datanode再也不向namenode进行汇报了。 有可能宕机了。
因为只要通过网络传输数据,就一定存在一种可能: 丢失 或者 延迟
HDFS的标准: 如果连续10次没有收到datnaode的汇报。 那么namenode就会认为该datanode存在宕机的可能
决定HDFS集群的启动时长会有两个因素:
1、磁盘元数据的大小
2、datanode的节点个数
当元数据很大,或者 节点个数很多的时候,那么HDFS的启动,需要一段很长的时间
在安全模式下:
如果一个操作涉及到元数据的修改的话。都不能
如果一个操作仅仅只是查询。那是被允许的。
所谓的安全模式,仅仅只是保护namenode 不是保护datanode
负载均衡:
1、节点均衡
2、机架均衡
3、磁盘均衡
HDFS工作原理:
HDFS写数据流程:
客户端要向HDFS写数据,首先要跟namenode通信,以确认可以写文件并获得接收文件block的datanode负责向其他datanode复制block的副本。
1、client发出写数据请求;
2、namenode响应请求,然后去metadata中查询文件目录树等一系列校验,如果能上传该数据,则返回该文件的所有切块应该被存放在哪些
datanode上的datanodes列表:
blk-001:hadoop02 hadoop03
blk-002:hadoop03 hadoop04
3、client拿到datanode列表之后,开始传输数据
4、首先是第一个块blk-001,datanode列表就是hadoop02 hadoop03;client就把blk-001传到hadoop02和hadoop03上;
5、用传第一个块的方式传其他的数据块;
6、当所有的数据块都传完之后,client会给namenode返回一个状态信息,表示数据以全部写入成功,或者是失败的信息;
7、namenode接收到client返回的状态信息来判断单词写入数据的请求是否成功,如果成功,就需要更新元数据信息。
详细的步骤说明:
1、使用HDFS提供的客户端client,向远程的namenode发起RPC请求;
2、namenode响应请求,然后去metadata中查询文件目录树等一系列校验,判断文件是否已经存在,创建者是否有权限进行操作,
成功则会为文件创建一个记录,否则会让客户端抛出异常;
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的副本数,写操作就会成功,并且这个块可以在集群中异步复制,直到达到其目标副本数,
因为namenode已知道文件有哪些块组成,所以它在返回成功前只需要等待数据块进行最小量的复制;
HDFS读数据流程:
客户端将要读取的文件路径发送给namenode,namenode获取文件的元信息(主要的存放位置信息)返回给客户端,
客户端根据返回的信息找到相应的datanode逐个获取文件的block并在客户端本地进行数据追加合并从而获取整个文件。
详细的操作步骤:
1、使用HDFS提供的客户端client,向远程的namenode发起RPC请求;
2、namenode会视情况返回文件的全部block列表,对于每个block,namenode都会返回有该block拷贝的datanode地址;
3、客户端client会选取离客户端最近的datanode来读取block;如果客户端本身就是datanode,那么将从本地直接获取数据;
4、读取完当前block的数据后,关闭当前的datanode链接,并为读取下一个block寻找最佳的datanode;
5、当读完列表block后,且文件读取还没有结束,客户端会继续向namenode获取下一批的block列表;
6、读取完一个block都会进行checksum验证,如果读取datanode是出现错误,客户端会通知namenode,然后再从下一个拥有
该block拷贝的datanode继续读;
NameNode的工作机制:
职责:
1、负责客户端请求的响应;
2、维护目录树结构(元数据);
3、配置和应用副本存放策略;
4、管理集群数据块负载均衡问题;
NameNode元数据管理
WAL:预写日志系统;
NameNode对数据的管理采用了两种存储形式:内存和磁盘
首先是内存中存储了一份完整的元数据,包括目录树结构,以及文件和数据块和副本存储的映射关系;
1、内存元数据metadata(全部存在内存中)
其次是在磁盘中也存储了一个份完成的元数据。有三种格式;
2、磁盘元数据镜像文件fsimage_0000000000000000555
3、数据历史操作日志文件edits: edits_0000000000000000001-0000000000000000018
(可以通过日志运算出元数据,全部存在磁盘中)
4、数据预写操作日志文件 edits_inprogress_0000000000000000556
(存储在磁盘中)
metadata = 最新的 fsimage_0000000000000000555 + edits_inprogress_0000000000000000556
metadata = 所有的edits之和(edits_001_002 + …… + edits_444_555 + edits_inprogress_556)
VERSION文件解析:(存放hdfs集群的版本信息)
#Sun Jan 06 20:12:30 CST 2017 ## 集群启动时间
namespaceID=844434736 ## 文件系统唯一标识符
clusterID=CID-5b7b7321-e43f-456e-bf41-18e77c5e5a40 ## 集群唯一标识符
cTime=0 ## fsimage 创建的时间,初始为 0,随 layoutVersion 更新
storageType=NAME_NODE ##节点类型
blockpoolID=BP-265332847-192.168.123.202-1483581570658 ## 数据块池 ID,可以有多个
layoutVersion=-60 ## hdfs 持久化数据结构的版本号
查看 edits 文件信息:
hdfs oev -i edits_0000000000000000482-0000000000000000483 -o edits.xml
cat edits.xml
查看 fsimage 镜像文件信息:
hdfs oiv -i fsimage_0000000000000000348 -p XML -o fsimage.xml
cat fsimage.xml
NameNode元数据存储机制:
A、内存中有一份完整的元数据(内存 metadata)
B、磁盘有一个准完整的元数据(fsiamge)文件(在namenode的工作目录中)
C、用于衔接内存metadata和持久化元数据镜像fsimage之间的操作日志(edits文件)
PS:当客户端对HDFS中的文件进行新增或者修改操作,操作记录首先被记入edits日志文件中,
当客户端操作成功之后,相应的元数据会更新到内存metadata中
元数据的CheckPoint:
每隔一段时间,会由secondary namenode将namenode上积累的所有edits和一个最新的fsimage下载到本地,
并加载到内存进行merge(这个过程称为checkpoint)
1、namenode把操作方在内存中处理速度更快,但是进程一旦杀掉内存中的数据会被清空,所以同时要把元数据信息
序列化到磁盘中。
2、但是如果操作时不断的进行序列化,会严重影响性能,所以采用只在开始时序列化一次的机制,之后的操作只存入日志。
3、之后只能把原镜像和日志文件合并即可,这部分操作由secondarynamenode完成,再把合并后的镜像返回给namenode即可;
所以namenode内有两个镜像和一堆日志文件;
过程:
1、secondarynamenode发起checkpoint请求;
2、namenode进行日志的处理,产生一个新的edits文件,checkpoint完成之前操作写入新的edits_improgress文件
3、将原来序列化镜像和eidts文件拷贝到secondarynamenode中,然后将两者合并出新的metadate;
4、将metadata序列化成新的fsimage文件;
5、将secondarynamenode中新产生的fsimage文件拷贝到namenode中。
重要配置参数:
dfs.namenode.checkpoint.check.period=60 ##检查触发条件是否满足的频率 60秒
dfs.namenode.checkpoint.period=3600 ##两次checkpoint之间的时间间隔3600秒
dfs.namenode.checkpoint.txns=1000000 ##两次checkpoint之间最大的操作记录
CheckPoint附带的作用:
NameNode和SecondaryNamenode的工作目录存储结构完全相同,所以当Namenode故障退出需要重新恢复时,
可以从SecondaryNamenode的工作目录中将fsimage拷贝到NameNode的工作目录,以恢复namenode的元数据。
DataNode工作机制:
1、工作职责:
存储管理用户的文件块数据
定期向namenode汇报自身所持有的block信息(通过心跳信息上报)
<property>
<!—HDFS 集群数据冗余块的自动删除时长,单位 ms,默认一个小时 -->
<name>dfs.blockreport.intervalMsec</name>
<value>3600000</value>
<description>Determines block reporting interval in milliseconds.</description>
</property>
2、DataNode掉线判断时限参数:就是心跳判断 默认 2 * 5min + 10 * 3s
block块信息地址:
/home/hadoop/hadoopdata/data/current/BP-771296455-192.168.123.106-1504830258603/curr
ent/finalized/subdir0/subdir0
**/