在现代的企业环境中,单机容量往往无法存储大量数据,需要跨机器存储。统一管理分布在集群上的文件系统称为分布式文件系统。
HDFS(Hadoop Distributed File System)是 Apache Hadoop 项目的一个子项目. Hadoop 非常适于存储大型数据 (比如 TB 和 PB), 其就是使用 HDFS 作为存储系统. HDFS 使用多台计算机存储文件, 并且提供统一的访问接口, 像是访问一个普通文件系统一样使用分布式文件系统.
1) 低延时的数据访问
对延时要求在毫秒级别的应用,不适合采用HDFS。HDFS是为高吞吐数据传输设计的,因此可能牺牲延时
2)大量小文件
文件的元数据保存在NameNode的内存中, 整个文件系统的文件数量会受限于NameNode的内存大小。
经验而言,一个文件/目录/文件块一般占有150字节的元数据内存空间。如果有100万个文件,每个文件占用1个文件块,则需要大约300M的内存。因此十亿级别的文件数量在现有商用机器上难以支持。
3)多方读写,需要任意的文件修改
HDFS采用追加(append-only)的方式写入数据。不支持文件任意offset的修改。不支持多个写入器(writer)
HDFS是一个【主/从(Mater/Slave)体系结构】,
HDFS由四部分组成,HDFS Client、NameNode、DataNode和Secondary NameNode。
1、Client:就是客户端。
2、NameNode:就是 master,它是一个主管、管理者。
3、DataNode:就是Slave。NameNode 下达命令,DataNode 执行实际的操作。
4、Secondary NameNode:并非 NameNode 的热备。当NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。
1、NameNode元数据信息
文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个文件的块列表。
以及列表中的块与块所在的DataNode之间的地址映射关系
在内存中加载文件系统中每个文件和每个数据块的引用关系(文件、block、datanode之间的映射信息)
数据会定期保存到本地磁盘(fsImage文件和edits文件)
2、NameNode文件操作
NameNode负责文件元数据的操作
DataNode负责处理文件内容的读写请求,数据流不经过NameNode,会询问它跟那个DataNode联系
3、NameNode副本
文件数据块到底存放到哪些DataNode上,是由NameNode决定的,NN根据全局情况做出放置副本的决定
4、NameNode心跳机制
全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包含该DataNode上所有数据块的列表)
若接受到心跳信息,NameNode认为DataNode工作正常,如果在10分钟后还接受到不到DN的心跳,那么NameNode认为DataNode已经宕机 ,这时候NN准备要把DN上的数据块进行重新的复制。 块的状态报告包含了一个DN上所有数据块的列表,blocks report 每个1小时发送一次.
提供真实文件数据的存储服务。
1、Data Node以数据块的形式存储HDFS文件
2、Data Node 响应HDFS 客户端读写请求
3、Data Node 周期性向NameNode汇报心跳信息
4、Data Node 周期性向NameNode汇报数据块信息
5、Data Node 周期性向NameNode汇报缓存数据块信息
所有的文件都是以 block 块的方式存放在 HDFS 文件系统当中,作用如下
在 Hadoop1 当中, 文件的 block 块默认大小是 64M, hadoop2 当中, 文件的 block 块大小默认是 128M, block 块的大小可以通过 hdfs-site.xml 当中的配置文件进行指定
<property>
<name>dfs.block.sizename>
<value>块大小 以字节为单位value>
property>
HDFS分布式文件系统的内部有一个副本存放策略:以默认的副本数=3为例:
1、第一个副本块存本机
2、第二个副本块存跟本机同机架内的其他服务器节点
格式 | 作用 |
---|---|
hdfs dfs -ls URI | 类似于Linux的ls命令,显示文件列表 |
[root@node01 test]# hdfs dfs -ls /
Found 1 items
drwxrwx--- - root supergroup 0 2020-06-26 08:57 /tmp
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -lsr URI | 在整个目录下递归执行ls, 与UNIX中的ls-R类似 |
[root@node01 test]# hdfs dfs -lsr /
lsr: DEPRECATED: Please use 'ls -R' instead.
drwxrwx--- - root supergroup 0 2020-06-26 08:57 /tmp
drwxrwx--- - root supergroup 0 2020-06-26 08:57 /tmp/hadoop-yarn
drwxrwx--- - root supergroup 0 2020-06-26 08:57 /tmp/hadoop-yarn/staging
drwxrwx--- - root supergroup 0 2020-06-26 08:57 /tmp/hadoop-yarn/staging/history
drwxrwx--- - root supergroup 0 2020-06-26 08:57 /tmp/hadoop-yarn/staging/history/done
drwxrwxrwt - root supergroup 0 2020-06-26 08:57 /tmp/hadoop-yarn/staging/history/done_intermediate
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs [-p] -mkdir | 以中的URI作为参数,创建目录。使用-p参数可以递归创建目录 |
[root@node01 test]# hdfs dfs -mkdir -p /aaa/bbb
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -put … | 将单个的源文件src或者多个源文件srcs从本地文件系统拷贝到目标文件系统中(对应的路径)。也可以从标准输入中读取输入,写入目标文件系统中 |
[root@node01 test]# hdfs dfs -put 1.txt /aaa
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -moveFromLocal | 和put命令类似,但是源文件localsrc拷贝之后自身被删除 |
[root@node01 test]# ls
1.txt
[root@node01 test]# hdfs dfs -moveFromLocal 1.txt /aaa/bbb
[root@node01 test]# ls
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -get [-ignorecrc ] [-crc] | 将文件拷贝到本地文件系统。 CRC 校验失败的文件通过-ignorecrc选项拷贝。 文件和CRC校验和可以通过-CRC选项拷贝 |
[root@node01 test]# ls
[root@node01 test]# hdfs dfs -get /aaa/bbb/1.txt .
[root@node01 test]# ls
1.txt
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -mv URI | 将hdfs上的文件从原路径移动到目标路径(移动之后文件删除),该命令不能夸文件系统 |
[root@node01 test]# hdfs dfs -mv /ccc /aaa/bbb/
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -rm [-r] 【-skipTrash】 URI 【URI 。。。】 | 删除参数指定的文件,参数可以有多个。 此命令只删除文件和非空目录。如果指定-skipTrash选项,那么在回收站可用的情况下,该选项将跳过回收站而直接删除文件;否则,在回收站可用时,在HDFS Shell 中执行此命令,会将文件暂时放到回收站中。 |
移除后自动放入到垃圾桶中
[root@node01 test]# hdfs dfs -rm -r /aaa
20/06/26 17:07:40 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/06/26 17:07:40 INFO fs.TrashPolicyDefault: Moved: 'hdfs://node01:8020/aaa' to trash at: hdfs://node01:8020/user/root/.Trash/Current/aaa
Moved: 'hdfs://node01:8020/aaa' to trash at: hdfs://node01:8020/user/root/.Trash/Current
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -cp URI [URI …] | 将文件拷贝到目标路径中。如果 为目录的话,可以将多个文件拷贝到该目录下。-f 选项将覆盖目标,如果它已经存在。-p 选项将保留文件属性(时间戳、所有权、许可、ACL、XAttr)。 |
[root@node01 test]# hdfs dfs -cp /aaa /bbb
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -cat URI [uri …] | 将参数所指示的文件内容输出到stdout |
[root@node01 test]# hdfs dfs -cat /aaa/1.txt
hello gcx!
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -chmod [-R] URI[URI …] | 改变文件权限。如果使用 -R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户。 |
[root@node01 test]# hdfs dfs -chmod 777 /aaa/1.txt
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -chmod [-R] URI[URI …] | 改变文件的所属用户和用户组。如果使用 -R 选项,则对整个目录有效递归执行。使用这一命令的用户必须是文件的所属用户,或者超级用户 |
[root@node01 test]# hdfs dfs -chown -R root:root /aaa/
[root@node01 test]#
格式 | 作用 |
---|---|
hdfs dfs -appendToFile … | 追加一个或者多个文件到hdfs指定文件中.也可以从命令行读取输入. |
[root@node01 test]# cat 1.xml
<gcx>hello</gcx>
[root@node01 test]# cat 2.xml
<gcxzflgl>world</gcxzflgl>
[root@node01 test]# hdfs dfs -appendToFile 1.xml 2.xml /merge.xml
[root@node01 test]# hdfs dfs -cat /merge.xml
<gcx>hello</gcx>
<gcxzflgl>world</gcxzflgl>
[root@node01 test]#
在多人共用HDFS的环境下,配置设置非常重要。特别是在Hadoop处理大量资料的环境,如果没有配额管理,很容易把所有的空间用完造成别人无法存取。Hdfs的配额设定是针对目录而不是针对账号,可以 让每个账号仅操作某一个目录,然后对目录设置配置。
HDFS文件的限额配置允许我们以文件个数,或者文件大小来限制我们在某个目录下上传的文件数量或者文件内容总量,以便达到我们类似百度网盘网盘等限制每个用户允许上传的最大的文件的量。
对文件夹bbb下查看文件数量限额查看,结果显示无上限
[root@node01 test]# hdfs dfs -count -q -h /bbb
none inf none inf 1 0 0 /bbb
[root@node01 test]#
给bbb文件夹设置存放两个文件的数量限额
[root@node01 test]# hdfs dfsadmin -setQuota 2 /bbb
#结果第二项显示只剩下1个文件的数量(hdfs认为文件夹bbb也是其中一项,所以只剩下一个存储文件数量限额)
[root@node01 test]# hdfs dfs -count -q -h /bbb
2 1 none inf 1 0 0 /bbb
[root@node01 test]#
给bbb文件夹放入两个文件
[root@node01 test]# ll
总用量 8
-rw-r--r--. 1 root root 17 6月 26 17:17 1.xml
-rw-r--r--. 1 root root 27 6月 26 17:17 2.xml
#放入一个文件
[root@node01 test]# hdfs dfs -put 1.xml /bbb
#文件数量限额为空
[root@node01 test]# hdfs dfs -count -q -h /bbb
2 0 none inf 1 1 17 /bbb
#再次放入一个文件,提示已经超出限额,不能再放入文件
[root@node01 test]# hdfs dfs -put 2.xml /bbb
put: The NameSpace quota (directories and files) of directory /bbb is exceeded: quota=2 file count=3
[root@node01 test]#
#清除限额
[root@node01 test]# hdfs dfsadmin -clrQuota /bbb
#放入因限额存储失败的文件,发现成功存入
[root@node01 test]# hdfs dfs -put 2.xml /bbb
[root@node01 test]#
#给ccc文件夹放入5k空间的限额
[root@node01 test]# hdfs dfsadmin -setSpaceQuota 5k /ccc
#查看文件的大小
[root@node01 test]# clear
[root@node01 test]# du -sh 1.xml
4.0K 1.xml
[root@node01 test]#
#存入小于5k限额的文件
[root@node01 test]# hdfs dfs -put 1.xml /ccc
#错误摘要
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.protocol.DSQuotaExceededException): The DiskSpace quota of /ccc is exceeded: quota = 5120 B = 5 KB but diskspace consumed = 402653184 B =
384 MB
我们对ccc文件夹设置了5k的空间限额,上传4k的文件夹提示报错,因为HDFS是分布式文件存储系统,默认进行分片存储,每片大小是128M,所以说至少需要384M才能存入成功
我们先清除对ccc文件夹5k的空间的限额,从新设定限额为384M
#清除空间限额
[root@node01 test]# hdfs dfsadmin -clrSpaceQuota /ccc
#设置空间大小限额384M
[root@node01 test]# hdfs dfsadmin -setSpaceQuota 384M /ccc
#上传4K的文件,经过分片处理需要384M大小空间,刚好存入ccc文件夹
[root@node01 test]# hdfs dfs -put 1.xml /ccc
[root@node01 test]#
附:生成任意大小的文件命令
dd if=/dev/zero of=1.txt bs=3M count=5 #生成15M的文件
安全模式是hadoop的一种保护机制,用于保证集群中的数据块的安全性。当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。
假设我们设置的副本数(即参数dfs.replication)是3,那么在datanode上就应该有3个副本存在,假设只存在2个副本,那么比例就是2/3=0.666。hdfs默认的副本率0.999。我们的副本率0.666明显小于0.999,因此系统会自动的复制副本到其他dataNode,使得副本率不小于0.999。如果系统中有5个副本,超过我们设定的3个副本,那么系统也会删除多于的2个副本。
在安全模式状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在,当整个系统达到安全标准时,HDFS自动离开安全模式。
hdfs dfsadmin -safemode get #查看安全模式状态
hdfs dfsadmin -safemode enter #进入安全模式
hdfs dfsadmin -safemode leave #离开安全模式
我们模拟下,服务异常处于安全模式状态情况下,对文件的读写
#开启安全模式
[root@node01 test]# hdfs dfsadmin -safemode enter
Safe mode is ON
#安全模式下删除文件。报错信息提示安全模式下,禁止操作,需要非安全模式下在操作
[root@node01 test]# hdfs dfs -rm -r /ccc
20/06/26 17:45:07 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/06/26 17:45:07 WARN fs.TrashPolicyDefault: Can't create trash directory: hdfs://node01:8020/user/root/.Trash/Current
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.server.namenode.SafeModeException): Cannot create directory /user/root/.Trash/Current. Name node is in safe mode.
It was turned on manually. Use "hdfs dfsadmin -safemode leave" to turn safe mode off.
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.checkNameNodeSafeMode(FSNamesystem.java:1335)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.mkdirs(FSNamesystem.java:3866)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.mkdirs(NameNodeRpcServer.java:984)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.mkdirs(ClientNamenodeProtocolServerSideTranslatorPB.java:634)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2217)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2213)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1754)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2211)
at org.apache.hadoop.ipc.Client.call(Client.java:1476)
at org.apache.hadoop.ipc.Client.call(Client.java:1413)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:229)
at com.sun.proxy.$Proxy10.mkdirs(Unknown Source)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.mkdirs(ClientNamenodeProtocolTranslatorPB.java:563)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:191)
at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:102)
at com.sun.proxy.$Proxy11.mkdirs(Unknown Source)
at org.apache.hadoop.hdfs.DFSClient.primitiveMkdir(DFSClient.java:3014)
at org.apache.hadoop.hdfs.DFSClient.mkdirs(DFSClient.java:2984)
at org.apache.hadoop.hdfs.DistributedFileSystem$21.doCall(DistributedFileSystem.java:1047)
at org.apache.hadoop.hdfs.DistributedFileSystem$21.doCall(DistributedFileSystem.java:1043)
at org.apache.hadoop.fs.FileSystemLinkResolver.resolve(FileSystemLinkResolver.java:81)
at org.apache.hadoop.hdfs.DistributedFileSystem.mkdirsInternal(DistributedFileSystem.java:1043)
at org.apache.hadoop.hdfs.DistributedFileSystem.mkdirs(DistributedFileSystem.java:1036)
at org.apache.hadoop.fs.TrashPolicyDefault.moveToTrash(TrashPolicyDefault.java:137)
at org.apache.hadoop.fs.Trash.moveToTrash(Trash.java:114)
at org.apache.hadoop.fs.Trash.moveToAppropriateTrash(Trash.java:95)
at org.apache.hadoop.fs.shell.Delete$Rm.moveToTrash(Delete.java:117)
at org.apache.hadoop.fs.shell.Delete$Rm.processPath(Delete.java:104)
at org.apache.hadoop.fs.shell.Command.processPaths(Command.java:317)
at org.apache.hadoop.fs.shell.Command.processPathArgument(Command.java:289)
at org.apache.hadoop.fs.shell.Command.processArgument(Command.java:271)
at org.apache.hadoop.fs.shell.Command.processArguments(Command.java:255)
at org.apache.hadoop.fs.shell.Command.processRawArguments(Command.java:201)
at org.apache.hadoop.fs.shell.Command.run(Command.java:165)
at org.apache.hadoop.fs.FsShell.run(FsShell.java:287)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:84)
at org.apache.hadoop.fs.FsShell.main(FsShell.java:340)
rm: Failed to move to trash: hdfs://node01:8020/ccc: Cannot create directory /user/root/.Trash/Current. Name node is in safe mode.
#退出安全模式
[root@node01 test]# hdfs dfsadmin -safemode leave
Safe mode is OFF
#删除文件成功
[root@node01 test]# hdfs dfs -rm -r /ccc
20/06/26 17:45:26 INFO fs.TrashPolicyDefault: Namenode trash configuration: Deletion interval = 10080 minutes, Emptier interval = 0 minutes.
20/06/26 17:45:26 INFO fs.TrashPolicyDefault: Moved: 'hdfs://node01:8020/ccc' to trash at: hdfs://node01:8020/user/root/.Trash/Current/ccc
Moved: 'hdfs://node01:8020/ccc' to trash at: hdfs://node01:8020/user/root/.Trash/Current
[root@node01 test]#
实际生产环境当中,hadoop的环境搭建完成之后,第一件事情就是进行压力测试,测试我们的集群的读取和写入速度,测试我们的网络带宽是否足够等一些基准测试
向HDFS文件系统中写入数据,10个文件,每个文件10MB,文件存放到/benchmarks/TestDFSIO中
hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -write -nrFiles 10 -fileSize 10MB
完成之后查看写入速度结果
hdfs dfs -text /benchmarks/TestDFSIO/io_write/part-00000
#也可以查看本地运行结果(机器硬件性能有关)
[root@node01 test]# cat TestDFSIO_results.log
----- TestDFSIO ----- : write
Date & time: Fri Jun 26 17:49:52 CST 2020
Number of files: 10
Total MBytes processed: 100
Throughput mb/sec: 1.56
Average IO rate mb/sec: 1.57
IO rate std deviation: 0.11
Test exec time sec: 126.33
[root@node01 test]#
测试hdfs的读取文件性能
在HDFS文件系统中读入10个文件,每个文件10M
hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -read -nrFiles 10 -fileSize 10MB
查看读取果
hdfs dfs -text /benchmarks/TestDFSIO/io_read/part-00000
#本地查看测试结果(机器硬件性能有关)
[root@node01 test]# cat TestDFSIO_results.log
----- TestDFSIO ----- : write
Date & time: Fri Jun 26 17:49:52 CST 2020
Number of files: 10
Total MBytes processed: 100
Throughput mb/sec: 1.56
Average IO rate mb/sec: 1.57 # 平均写入速度1.57M每秒
IO rate std deviation: 0.11
Test exec time sec: 126.33 # 总共执行时间
----- TestDFSIO ----- : read
Date & time: Fri Jun 26 17:54:02 CST 2020
Number of files: 10
Total MBytes processed: 100
Throughput mb/sec: 28.7
Average IO rate mb/sec: 50.3 # 平均读取速度50.3M每秒
IO rate std deviation: 71.05
Test exec time sec: 89.49 # 总共执行时间
[root@node01 test]#
hadoop jar /export/servers/hadoop-2.7.5/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.7.5.jar TestDFSIO -clean
文字叙述:
1.client请求上传文件a.txt
2.namenode校验上传权限(上传的文件在指定目录下是否存在)
3.校验通过返回client告知可以上传
4.将待上传的文件进行切片(默认128切分成3块),请求上传block1
5.namenodeg根据集群中datanode中的block信息和机架感知,选择可以上传的三个主机
6.返回给client可以上传的datanode主机列表
7.client与datanode进行pipeline 建立
8.client向datanode传递数据(packet单位64k)同时也传递给其他datanode
9.datanode将传递进来的文件进行缓存。存储在本地文件中
10.datanode每次接受一个packet的数据进行进行应答
11.block2重复进行4-10过程
文字叙述:
1.client请求namenode下载a.txt
2.namenode进行权限检查(文件切分block后分布在的主机列表)
3.优先本机寻找是否存在block,没有按照一定的策略读取datanode主机
4.和选出的datanode进行并行的pipeline连接
5.并行读取数据(packet:64k)
6.将读取的数据进行合并成一个大文件,返回给client
当 Hadoop 的集群当中, NameNode的所有元数据信息都保存在了 FsImage 与 Eidts 文件当中, 这两个文件就记录了所有的数据的元数据信息, 元数据信息的保存目录配置在了 hdfs-site.xml 当中
<property>
<name>dfs.namenode.name.dir</name>
<value>
file:///export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas, file:///export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas2
</value>
</property>
<property>
<name>dfs.namenode.edits.dir</name>
<value>file:///export/servers/hadoop-2.7.5/hadoopDatas/nn/edits
</property>>
使用命令 hdfs oiv
cd /export/servers/hadoop-2.7.5/hadoopDatas/namenodeDatas/current
hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml
使用命令 hdfs oev
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas/current
hdfs oev -i edits_0000000000000000865-0000000000000000866 -p XML -o myedit.xml
SecondaryNameNode 定期合并 fsimage 和 edits, 把 edits 控制在一个范围内
配置 SecondaryNameNode
SecondaryNameNode 在 conf/masters 中指定
在 masters 指定的机器上, 修改 hdfs-site.xml
<property>
<name>dfs.http.addressname>
<value>host:50070value>
property>
修改 core-site.xml, 这一步不做配置保持默认也可以
<property>
<name>fs.checkpoint.periodname>
<value>3600value>
property>
<property>
<name>fs.checkpoint.sizename>
<value>67108864value>
property>
Hadoop linux编译后windows运行版本下载链接:链接:https://pan.baidu.com/s/1qMtCSBQYeDB-lpor4fadCQ
提取码:4epc
在windows系统需要配置hadoop运行环境,否则直接运行代码会出现以下问题:
缺少winutils.exe
Could not locate executable null \bin\winutils.exe in the hadoop binaries
缺少hadoop.dll
Unable to load native-hadoop library for your platform… using builtin-Java classes where applicable
步骤:
第一步:将hadoop2.7.5文件夹拷贝到一个没有中文没有空格的路径下面
第二步:在windows上面配置hadoop的环境变量: HADOOP_HOME,并将%HADOOP_HOME%\bin添加到path中
第三步:把hadoop2.7.5文件夹中bin目录下的hadoop.dll文件放到系统盘: C:\Windows\System32 目录
第四步:关闭windows重启
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<!-- <verbal>true</verbal>-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
在 Java 中操作 HDFS, 主要涉及以下 Class:
Configuration
FileSystem
该类的对象是一个文件系统对象, 可以用该对象的一些方法来对文件进行操作, 通过 FileSystem 的静态方法 get 获得该对象
FileSystem fs = FileSystem.get(conf)
@Test
public void getFileSystem1() throws IOException {
Configuration configuration = new Configuration();
//指定我们使用的文件系统类型:
configuration.set("fs.defaultFS", "hdfs://node01:8020/");
//获取指定的文件系统
FileSystem fileSystem = FileSystem.get(configuration);
System.out.println(fileSystem.toString());
}
@Test
public void getFileSystem2() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
System.out.println("fileSystem:"+fileSystem);
}
@Test
public void getFileSystem3() throws Exception{
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS", "hdfs://node01:8020");
FileSystem fileSystem = FileSystem.newInstance(configuration);
System.out.println(fileSystem.toString());
}
//@Test
public void getFileSystem4() throws Exception{
FileSystem fileSystem = FileSystem.newInstance(new URI("hdfs://node01:8020") ,new Configuration());
System.out.println(fileSystem.toString());
}
@Test
public void listMyFiles()throws Exception{
//获取fileSystem类
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
//获取RemoteIterator 得到所有的文件或者文件夹,第一个参数指定遍历的路径,第二个参数表示是否要递归遍历
RemoteIterator<LocatedFileStatus> locatedFileStatusRemoteIterator = fileSystem.listFiles(new Path("/"), true);
while (locatedFileStatusRemoteIterator.hasNext()){
LocatedFileStatus next = locatedFileStatusRemoteIterator.next();
System.out.println(next.getPath().toString());
}
fileSystem.close();
}
@Test
public void mkdirs() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
boolean mkdirs = fileSystem.mkdirs(new Path("/hello/mydir/test"));
fileSystem.close();
}
@Test
public void getFileToLocal()throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
FSDataInputStream inputStream = fileSystem.open(new Path("/timer.txt"));
FileOutputStream outputStream = new FileOutputStream(new File("e:\\timer.txt"));
IOUtils.copy(inputStream,outputStream );
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
fileSystem.close();
}
@Test
public void putData() throws Exception{
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());
fileSystem.copyFromLocalFile(new Path("file:///c:\\install.log"),new Path("/hello/mydir/test"));
fileSystem.close();
}
由于 Hadoop 擅长存储大文件,因为大文件的元数据信息比较少,如果 Hadoop 集群当中有大量的小文件,那么每个小文件都需要维护一份元数据信息,会大大的增加集群管理元数据的内存压力,所以在实际工作当中,如果有必要一定要将小文件合并成大文件进行一起处理
在我们的 HDFS 的 Shell 命令模式下,可以通过命令行将很多的 hdfs 文件合并成一个大文件下载到本地
cd /export/servers
hdfs dfs -getmerge /*.txt ./hello.txt
既然可以在下载的时候将这些小文件合并成一个大文件一起下载,那么肯定就可以在上传的时候将小文件合并到一个大文件里面去
@Test
public void mergeFile() throws Exception{
//获取分布式文件系统
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration(),"root");
FSDataOutputStream outputStream = fileSystem.create(new Path("/bigfile.txt"));
//获取本地文件系统
LocalFileSystem local = FileSystem.getLocal(new Configuration());
//通过本地文件系统获取文件列表,为一个集合
FileStatus[] fileStatuses = local.listStatus(new Path("file:///E:\\input"));
for (FileStatus fileStatus : fileStatuses) {
FSDataInputStream inputStream = local.open(fileStatus.getPath());
IOUtils.copy(inputStream,outputStream);
IOUtils.closeQuietly(inputStream);
}
IOUtils.closeQuietly(outputStream);
local.close();
fileSystem.close();
}
在Hadoop 中,NameNode 所处的位置是非常重要的,整个HDFS文件系统的元数据信息都由NameNode 来管理,NameNode的可用性直接决定了Hadoop 的可用性,一旦NameNode进程不能工作了,就会影响整个集群的正常使用。
在典型的HA集群中,两台独立的机器被配置为NameNode。在工作集群中,NameNode机器中的一个处于Active状态,另一个处于Standby状态。Active NameNode负责群集中的所有客户端操作,而Standby充当从服务器。Standby机器保持足够的状态以提供快速故障切换。
ZKFailoverController
是基于Zookeeper的故障转移控制器,它负责控制NameNode的主备切换,ZKFailoverController会监测NameNode的健康状态,当发现Active NameNode出现异常时会通过Zookeeper进行一次新的选举,完成Active和Standby状态的切换
HealthMonitor
周期性调用NameNode的HAServiceProtocol RPC接口(monitorHealth 和 getServiceStatus),监控NameNode的健康状态并向ZKFailoverController反馈
ActiveStandbyElector
接收ZKFC的选举请求,通过Zookeeper自动完成主备选举,选举完成后回调ZKFailoverController的主备切换方法对NameNode进行Active和Standby状态的切换.
DataNode
NameNode包含了HDFS的元数据信息和数据块信息(blockmap),其中数据块信息通过DataNode主动向Active NameNode和Standby NameNode上报
共享存储系统
共享存储系统负责存储HDFS的元数据(EditsLog),Active NameNode(写入)和 Standby NameNode(读取)通过共享存储系统实现元数据同步,在主备切换过程中,新的Active NameNode必须确保元数据同步完成才能对外提供服务
高可用架构图:
HA namenode切换简易文字叙述:
通过zk监听namenode的状态,一旦掉线通过HealthMonitor上报ZKFailoverController,ActiveStandbyElector上报给zookeeper,zookeeper进行投票选举,选举出新的namenode,同时也告知崩溃的namenode状态切换成standby。
高可用集群搭建文档:
链接:https://pan.baidu.com/s/1pcMYSu-yMWjVGPhacF4PnA
提取码:ivqr
##3: Hadoop的联邦机制(Federation)
单NameNode的架构使得HDFS在集群扩展性和性能上都有潜在的问题,当集群大到一定程度后,NameNode进程使用的内存可能会达到上百G,NameNode成为了性能的瓶颈。因而提出了namenode水平扩展方案-- Federation。
Federation中文意思为联邦,联盟,是NameNode的Federation,也就是会有多个NameNode。多个NameNode的情况意味着有多个namespace(命名空间),区别于HA模式下的多NameNode,它们是拥有着同一个namespace。既然说到了NameNode的命名空间的概念,这里就看一下现有的HDFS数据管理架构,如下图所示:
从上图中,我们可以很明显地看出现有的HDFS数据管理,数据存储2层分层的结构.也就是说,所有关于存储数据的信息和管理是放在NameNode这边,而真实数据的存储则是在各个DataNode下.而这些隶属于同一个NameNode所管理的数据都是在同一个命名空间下的.而一个namespace对应一个block pool。Block Pool是同一个namespace下的block的集合.当然这是我们最常见的单个namespace的情况,也就是一个NameNode管理集群中所有元数据信息的时候.如果我们遇到了之前提到的NameNode内存使用过高的问题,这时候怎么办?元数据空间依然还是在不断增大,一味调高NameNode的jvm大小绝对不是一个持久的办法.这时候就诞生了HDFS Federation的机制.
HDFS Federation是解决namenode内存瓶颈问题的水平横向扩展方案。
Federation意味着在集群中将会有多个namenode/namespace。这些namenode之间是联合的,也就是说,他们之间相互独立且不需要互相协调,各自分工,管理自己的区域。分布式的datanode被用作通用的数据块存储存储设备。每个datanode要向集群中所有的namenode注册,且周期性地向所有namenode发送心跳和块报告,并执行来自所有namenode的命令。
Federation一个典型的例子就是上面提到的NameNode内存过高问题,我们完全可以将上面部分大的文件目录移到另外一个NameNode上做管理.更重要的一点在于,这些NameNode是共享集群中所有的DataNode的,它们还是在同一个集群内的**。**
这时候在DataNode上就不仅仅存储一个Block Pool下的数据了,而是多个(在DataNode的datadir所在目录里面查看BP-xx.xx.xx.xx打头的目录)。
概括起来:
多个NN共用一个集群里的存储资源,每个NN都可以单独对外提供服务。
每个NN都会定义一个存储池,有单独的id,每个DN都为所有存储池提供存储。
DN会按照存储池id向其对应的NN汇报块信息,同时,DN会向所有NN汇报本地存储可用资源情况。
HDFS Federation不足
HDFS Federation并没有完全解决单点故障问题。虽然namenode/namespace存在多个,但是从单个namenode/namespace看,仍然存在单点故障:如果某个namenode挂掉了,其管理的相应的文件便不可以访问。Federation中每个namenode仍然像之前HDFS上实现一样,配有一个secondary namenode,以便主namenode挂掉一下,用于还原元数据信息。
所以一般集群规模真的很大的时候,会采用HA+Federation的部署方案。也就是每个联合的namenodes都是ha的。
至此,HDFS核心内容讲解完毕!