这篇主要聊一下Hadoop分布式文件系统—HDFS
大纲:
1.HDFS设计目标
2.HDFS里面的NameNode和DataNode
3.操作HDFS的两种方式
1.HDFS设计目标
硬件错误
硬件错误是常态而不是异常。(每每读这句我就想到了:程序员加班是常态不是异常)HDFS可能由成百上千的服务器所构成,每个服务器上存储着文件系统的部分数据。我们面对的现实是构成系统的组件数目是巨大的,而且任一组件都有可能失效,这意味着总是有一部分HDFS的组件是不工作的。因此错误检测和快速、自动的恢复是HDFS最核心的架构目标。
流式数据访问
HDFS结构思路是“一次写入,多次读取”。因为hadoop被用来分析久数据,每次分析都涉及到大部分数据集或者整个数据集,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要,即:宁愿开始读取数据慢,但是读取整个数据快,也不希望很快读取开始的数据,但是后面的数据读取很慢。
大规模数据集
超大文件GB,TB,PB级的数据
简单的一致性模型
HDFS应用需要一个“一次写入多次读取”的文件访问模型。一个文件经过创建、写入和关闭之后就不需要改变。这一假设简化了数据一致性问题,并且使高吞吐量的数据访问成为可能。Map/Reduce应用或者网络爬虫应用都非常适合这个模型。目前还有计划在将来扩充这个模型,使之支持文件的附加写操作。
“移动计算比移动数据更划算”
计算节点和数据节点在同一个计算中,减少网络中数据交换,带来更快的速度
异构软硬件平台间的可移植性
HDFS在设计的时候就考虑到平台的可移植性。这种特性方便了HDFS作为大规模数据应用平台的推广。
有了hadoop,让上面得以实现
2.HDFS中的NameNode和DataNode
HDFS采用的master/slave架构。一个HDFS集群是由一个Namenode和一定数目的Datanodes组成。Namenode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的Datanode一般是一个节点(节点的含义可以理解为一个主机)一个,负责管理它所在节点上的存储。HDFS暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。从内部看,一个文件其实被分成一个或多个数据块,这些块存储在一组Datanode上。Namenode执行文件系统的名字空间操作,比如打开、关闭、重命名文件或目录。它也负责确定数据块到具体Datanode节点的映射。Datanode负责处理文件系统客户端的读写请求。在Namenode的统一调度下进行数据块的创建、删除和复制。
数据块:我们知道计算机的磁盘都有默认数据块的大小,文件系统块的大小是磁盘块的整数倍,一般为几千字节,而磁盘块一般为512字节。HDFS也有块的概念,默认是64MB。为什么会这么大了?大家都知道,磁盘之所以比较慢是因为磁盘的读写是机械的而hadoop主要是用来处理大数据的,为了节省寻址时间,所以将一大块数据放在一起,这样可以节省处理数据的时间。
hadoop提供了一个综合的文件系统抽象,提供了文件系统实现的各类接口。HDFS只是这个抽象文件系统的一个实现
举一个例子:
现在我要保存一个2G的电影,上传到HDFS上的流程是怎么样的呢?
1.HDFS为了数据安全性,默认情况下会将这个电影保存3份(我们取个名字:原电影,备份一,备份二)。这个备份数是可以调整的。
2.2G的电影数据被切割成32份保存在DataNode中。这个电影的信息保存在NameNode中
3.原电影和备份一会放在同一个机架上,备份二放在另一个机架上。这样如果原电影因为某些原因数据丢失,还可以找到备份一(优势:速度快,避免数据在网络中传输),在差一点如果机架因为天灾坏了,我们还有第二个机架可以找到数据(优势:保证安全)
3.实际操作HDFS
先把hadoo运行起来
- [root@master ~]# su hadoop //切换到hadoop用户
- [hadoop@master root]$ cd /usr/hadoop/hadoop-1.0.4/bin //进入bin目录
- [hadoop@master bin]$ ls
- hadoop start-all.sh stop-balancer.sh
- hadoop-config.sh start-balancer.sh stop-dfs.sh
- hadoop-daemon.sh start-dfs.sh stop-jobhistoryserver.sh
- hadoop-daemons.sh start-jobhistoryserver.sh stop-mapred.sh
- rcc start-mapred.sh task-controller
- slaves.sh stop-all.sh
- [hadoop@master bin]$ ./start-all.sh //启动
- starting namenode, logging to /usr/hadoop/hadoop-1.0.4/libexec/../logs/hadoop-hadoop-namenode-master.hadoop.out
- 192.168.81.129: starting datanode, logging to /usr/hadoop/hadoop-1.0.4/libexec/../logs/hadoop-hadoop-datanode-slave01.hadoop.out
- 192.168.81.130: ssh: connect to host 192.168.81.130 port 22: No route to host
- 192.168.81.131: ssh: connect to host 192.168.81.131 port 22: No route to host
- 192.168.81.128: starting secondarynamenode, logging to /usr/hadoop/hadoop-1.0.4/libexec/../logs/hadoop-hadoop-secondarynamenode-master.hadoop.out
- starting jobtracker, logging to /usr/hadoop/hadoop-1.0.4/libexec/../logs/hadoop-hadoop-jobtracker-master.hadoop.out
- 192.168.81.129: starting tasktracker, logging to /usr/hadoop/hadoop-1.0.4/libexec/../logs/hadoop-hadoop-tasktracker-slave01.hadoop.out
- 192.168.81.130: ssh: connect to host 192.168.81.130 port 22: No route to host
- 192.168.81.131: ssh: connect to host 192.168.81.131 port 22: No route to host
- [hadoop@master bin]$
操作HDFS的方式这里介绍两种方式:
1.FS shell
在这里提供详细的FS shell脚本
cat
使用方法:hadoop fs -cat URI [URI …]
将路径指定文件的内容输出到stdout。
示例:
- hadoop fs -cat hdfs://host1:port1/file1 hdfs://host2:port2/file2
- hadoop fs -cat file:///file3 /user/hadoop/file4
返回值:
-->成功返回0,失败返回-1。
chgrp
使用方法:hadoop fs -chgrp [-R] GROUP URI [URI …]
改变文件所属的组。使用-R将使改变在目录结构下递归进行。命令的使用者必须是文件的所有者或者超级用户。
chmod
使用方法:hadoop fs -chmod [-R] <MODE[,MODE]... | OCTALMODE> URI [URI …]
改变文件的权限。使用-R将使改变在目录结构下递归进行。命令的使用者必须是文件的所有者或者超级用户。
chown
使用方法:hadoop fs -chown [-R] [OWNER][:[GROUP]] URI [URI ]
改变文件的拥有者。使用-R将使改变在目录结构下递归进行。命令的使用者必须是超级用户。
copyFromLocal
使用方法:hadoop fs -copyFromLocal <localsrc> URI
除了限定源路径是一个本地文件外,和put命令相似。
copyToLocal
使用方法:hadoop fs -copyToLocal [-ignorecrc] [-crc] URI <localdst>
除了限定目标路径是一个本地文件外,和get命令类似。
cp
使用方法:hadoop fs -cp URI [URI …] <dest>
将文件从源路径复制到目标路径。这个命令允许有多个源路径,此时目标路径必须是一个目录。
示例:
- hadoop fs -cp /user/hadoop/file1 /user/hadoop/file2
- hadoop fs -cp /user/hadoop/file1 /user/hadoop/file2 /user/hadoop/dir
返回值:
成功返回0,失败返回-1。
du
使用方法:hadoop fs -du URI [URI …]
显示目录中所有文件的大小,或者当只指定一个文件时,显示此文件的大小。
示例:
hadoop fs -du /user/hadoop/dir1 /user/hadoop/file1 hdfs://host:port/user/hadoop/dir1
返回值:
成功返回0,失败返回-1。
dus
使用方法:hadoop fs -dus <args>
显示文件的大小。
expunge
使用方法:hadoop fs -expunge
清空回收站。请参考HDFS设计文档以获取更多关于回收站特性的信息。
get
使用方法:hadoop fs -get [-ignorecrc] [-crc] <src> <localdst>
复制文件到本地文件系统。可用-ignorecrc选项复制CRC校验失败的文件。使用-crc选项复制文件以及CRC信息。
示例:
- hadoop fs -get /user/hadoop/file localfile
- hadoop fs -get hdfs://host:port/user/hadoop/file localfile
返回值:
成功返回0,失败返回-1。
getmerge
使用方法:hadoop fs -getmerge <src> <localdst> [addnl]
接受一个源目录和一个目标文件作为输入,并且将源目录中所有的文件连接成本地目标文件。addnl是可选的,用于指定在每个文件结尾添加一个换行符。
ls
使用方法:hadoop fs -ls <args>
如果是文件,则按照如下格式返回文件信息:
文件名 <副本数> 文件大小 修改日期 修改时间 权限 用户ID 组ID
如果是目录,则返回它直接子文件的一个列表,就像在Unix中一样。目录返回列表的信息如下:
目录名 <dir> 修改日期 修改时间 权限 用户ID 组ID
示例:
hadoop fs -ls /user/hadoop/file1 /user/hadoop/file2 hdfs://host:port/user/hadoop/dir1 /nonexistentfile
返回值:
成功返回0,失败返回-1。
lsr
使用方法:hadoop fs -lsr <args>
ls命令的递归版本。类似于Unix中的ls -R。
mkdir
使用方法:hadoop fs -mkdir <paths>
接受路径指定的uri作为参数,创建这些目录。其行为类似于Unix的mkdir -p,它会创建路径中的各级父目录。
示例:
- hadoop fs -mkdir /user/hadoop/dir1 /user/hadoop/dir2
- hadoop fs -mkdir hdfs://host1:port1/user/hadoop/dir hdfs://host2:port2/user/hadoop/dir
返回值:
成功返回0,失败返回-1。
movefromLocal
使用方法:dfs -moveFromLocal <src> <dst>
输出一个”not implemented“信息。
mv
使用方法:hadoop fs -mv URI [URI …] <dest>
将文件从源路径移动到目标路径。这个命令允许有多个源路径,此时目标路径必须是一个目录。不允许在不同的文件系统间移动文件。
示例:
- hadoop fs -mv /user/hadoop/file1 /user/hadoop/file2
- hadoop fs -mv hdfs://host:port/file1 hdfs://host:port/file2 hdfs://host:port/file3 hdfs://host:port/dir1
返回值:
成功返回0,失败返回-1。
put
使用方法:hadoop fs -put <localsrc> ... <dst>
从本地文件系统中复制单个或多个源路径到目标文件系统。也支持从标准输入中读取输入写入目标文件系统。
- hadoop fs -put localfile /user/hadoop/hadoopfile
- hadoop fs -put localfile1 localfile2 /user/hadoop/hadoopdir
- hadoop fs -put localfile hdfs://host:port/hadoop/hadoopfile
- hadoop fs -put - hdfs://host:port/hadoop/hadoopfile
从标准输入中读取输入。
返回值:
成功返回0,失败返回-1。
rm
使用方法:hadoop fs -rm URI [URI …]
删除指定的文件。只删除非空目录和文件。请参考rmr命令了解递归删除。
示例:
- hadoop fs -rm hdfs://host:port/file /user/hadoop/emptydir
返回值:
成功返回0,失败返回-1。
rmr
使用方法:hadoop fs -rmr URI [URI …]
delete的递归版本。
示例:
- hadoop fs -rmr /user/hadoop/dir
- hadoop fs -rmr hdfs://host:port/user/hadoop/dir
返回值:
成功返回0,失败返回-1。
setrep
使用方法:hadoop fs -setrep [-R] <path>
改变一个文件的副本系数。-R选项用于递归改变目录下所有文件的副本系数。
示例:
- hadoop fs -setrep -w 3 -R /user/hadoop/dir1
返回值:
成功返回0,失败返回-1。
stat
使用方法:hadoop fs -stat URI [URI …]
返回指定路径的统计信息。
示例:
- hadoop fs -stat path
返回值:
成功返回0,失败返回-1。
tail
使用方法:hadoop fs -tail [-f] URI
将文件尾部1K字节的内容输出到stdout。支持-f选项,行为和Unix中一致。
示例:
- hadoop fs -tail pathname
返回值:
成功返回0,失败返回-1。
test
使用方法:hadoop fs -test -[ezd] URI
选项:
-e 检查文件是否存在。如果存在则返回0。
-z 检查文件是否是0字节。如果是则返回0。
-d 如果路径是个目录,则返回1,否则返回0。
示例:
- hadoop fs -test -e filename
text
使用方法:hadoop fs -text <src>
将源文件输出为文本格式。允许的格式是zip和TextRecordInputStream。
touchz
使用方法:hadoop fs -touchz URI [URI …]
创建一个0字节的空文件。
示例:
- hadoop -touchz pathname
返回值:
成功返回0,失败返回-1。
2.Java操作HDFS
首先将hadoop下lib里面的jar包都复制到Java项目中
- package com.sxt.hdfs;
- import java.io.IOException;
- import org.apache.hadoop.conf.Configuration;
- import org.apache.hadoop.fs.FSDataInputStream;
- import org.apache.hadoop.fs.FSDataOutputStream;
- import org.apache.hadoop.fs.FileSystem;
- import org.apache.hadoop.fs.Path;
- import org.apache.hadoop.mapreduce.lib.db.DBInputFormat;
- /**
- *
- * @title HelloWordHDFS
- * @description 入门hadoop的HDFS
- * @author hadoop
- * @version
- * @copyright (c) SINOSOFT
- *
- */
- public class HelloWordHDFS {
- /**
- * 操作文件无非就是增加文件,修改文件,删除文件,查找文件
- */
- /**
- * 增加一个文件
- * @throws Exception
- */
- public void addFile() throws Exception{
- //加载配置文件
- Configuration conf = new Configuration();
- FileSystem fs = FileSystem.get(conf);
- Path path = new Path("/user/helloHDFS/test.txt");
- //直接新建一个空白文件
- fs.createNewFile(path);
- //更多的时候项目中是从一个地方将文件复制到另一个地方
- Path sou = new Path("d://SALES.DMP");
- Path tag = new Path("/user/helloHDFS");
- fs.copyFromLocalFile(sou, tag);
- fs.close();
- }
- /**
- *
- * @title updateFile
- * @description 修改文件,我们在文件末尾追加
- * @author hadoop
- * @throws Exception
- */
- public void updateFile() throws Exception{
- Configuration conf = new Configuration();
- FileSystem fs = FileSystem.get(conf);
- Path path = new Path("/user/helloHDFS/test.txt");
- FSDataOutputStream out = fs.append(path);
- out.writeChars("中文jkjkjk#$%^**(((");
- out.flush();
- out.close();
- fs.close();
- }
- /**
- *
- * @title deleteFile
- * @description 删除一个文件
- * @author hadoop
- * @throws Exception
- */
- public void deleteFile()throws Exception{
- Configuration conf = new Configuration();
- FileSystem fs = FileSystem.get(conf);
- Path path = new Path("/user/hadoop/111.txt");
- fs.deleteOnExit(path);
- fs.close();
- }
- /**
- *
- * @title readFile
- * @description 读取文件
- * @author hadoop
- * @throws Exception
- */
- public void readFile()throws Exception{
- Configuration conf = new Configuration();
- FileSystem fs = FileSystem.get(conf);
- FSDataInputStream input = fs.open(new Path("/user/helloHDFS/test.txt"));
- String temp = "";
- System.err.println(new String (input.readLine().getBytes("ISO-8859-1"),"gb2312"));
- // System.err.println(new String(b));
- // System.err.println(temp);
- }
- public void testDB()throws Exception{
- Configuration conf = new Configuration();
- FileSystem fs = FileSystem.get(conf);
- // DBInputFormat<DBWritable>
- }
- public static void main(String[] args) throws Exception {
- HelloWordHDFS hw = new HelloWordHDFS();
- //1.测试增加文件
- //hw.addFile();
- //2.测试更新文件
- // for(int i = 0 ; i < 5 ; i++){
- // hw.updateFile();
- // }
- //3.测试删除文件
- // hw.deleteFile();
- //4.测试读取文件
- // hw.readFile();
- }
- }