本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文链接,博主为石山园,博客地址为 http://www.cnblogs.com/shishanyuan 。该系列课程是应邀实验楼整理编写的,这里须要赞一下实验楼提供了学习的新方式,能够边看博客边上机实验,课程地址为 https://www.shiyanlou.com/courses/237java
【注】该系列所使用到安装包、测试数据和代码都可在百度网盘下载,具体地址为 http://pan.baidu.com/s/10PnDs,下载该PDF文件node
部署节点操做系统为CentOS,防火墙和SElinux禁用,建立了一个shiyanlou用户并在系统根目录下建立/app目录,用于存放Hadoop等组件运行包。由于该目录用于安装hadoop等组件程序,用户对shiyanlou必须赋予rwx权限(通常作法是root用户在根目录下建立/app目录,并修改该目录拥有者为shiyanlou(chown –R shiyanlou:shiyanlou /app)。linux
Hadoop搭建环境:apache
l 虚拟机操做系统: CentOS6.6 64位,单核,1G内存服务器
l JDK:1.7.0_55 64位架构
l Hadoop:1.1.2app
HDFS(Hadoop Distributed File System)是一个分布式文件系统,是谷歌的GFS山寨版本。它具备高容错性并提供了高吞吐量的数据访问,很是适合大规模数据集上的应用,它提供了一个高度容错性和高吞吐量的海量数据存储解决方案。分布式
l高吞吐量访问:HDFS的每一个Block分布在不一样的Rack上,在用户访问时,HDFS会计算使用最近和访问量最小的服务器给用户提供。因为Block在不一样的Rack上都有备份,因此再也不是单数据访问,因此速度和效率是很是快的。另外HDFS能够并行从服务器集群中读写,增长了文件读写的访问带宽。ide
l高容错性:系统故障是不可避免的,如何作到故障以后的数据恢复和容错处理是相当重要的。HDFS经过多方面保证数据的可靠性,多份复制而且分布到物理位置的不一样服务器上,数据校验功能、后台的连续自检数据一致性功能都为高容错提供了可能。oop
l线性扩展:由于HDFS的Block信息存放到NameNode上,文件的Block分布到DataNode上,当扩充的时候仅仅添加DataNode数量,系统能够在不中止服务的状况下作扩充,不须要人工干预。
如上图所示HDFS是Master和Slave的结构,分为NameNode、Secondary NameNode和DataNode三种角色。
lNameNode:在Hadoop1.X中只有一个Master节点,管理HDFS的名称空间和数据块映射信息、配置副本策略和处理客户端请求;
lSecondary NameNode:辅助NameNode,分担NameNode工做,按期合并fsimage和fsedits并推送给NameNode,紧急状况下可辅助恢复NameNode;
lDataNode:Slave节点,实际存储数据、执行数据块的读写并汇报存储信息给NameNode;
1. 客户端经过调用FileSystem对象的open()方法来打开但愿读取的文件,对于HDFS来讲,这个对象时分布文件系统的一个实例;
2. DistributedFileSystem经过使用RPC来调用NameNode以肯定文件起始块的位置,同一Block按照重复数会返回多个位置,这些位置按照Hadoop集群拓扑结构排序,距离客户端近的排在前面;
3. 前两步会返回一个FSDataInputStream对象,该对象会被封装成DFSInputStream对象,DFSInputStream能够方便的管理datanode和namenode数据流,客户端对这个输入流调用read()方法;
4. 存储着文件起始块的DataNode地址的DFSInputStream随即链接距离最近的DataNode,经过对数据流反复调用read()方法,能够将数据从DataNode传输到客户端;
5. 到达块的末端时,DFSInputStream会关闭与该DataNode的链接,而后寻找下一个块的最佳DataNode,这些操做对客户端来讲是透明的,客户端的角度看来只是读一个持续不断的流;
6. 一旦客户端完成读取,就对FSDataInputStream调用close()方法关闭文件读取。
1. 客户端经过调用DistributedFileSystem的create()方法建立新文件;
2. DistributedFileSystem经过RPC调用NameNode去建立一个没有Blocks关联的新文件,建立前NameNode会作各类校验,好比文件是否存在、客户端有无权限去建立等。若是校验经过,NameNode会为建立新文件记录一条记录,不然就会抛出IO异常;
3. 前两步结束后会返回FSDataOutputStream的对象,和读文件的时候类似,FSDataOutputStream被封装成DFSOutputStream,DFSOutputStream能够协调NameNode和Datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小的数据包,并写入内部队列称为“数据队列”(Data Queue);
4. DataStreamer会去处理接受Data Queue,它先问询NameNode这个新的Block最适合存储的在哪几个DataNode里,好比重复数是3,那么就找到3个最适合的DataNode,把他们排成一个pipeline.DataStreamer把Packet按队列输出到管道的第一个Datanode中,第一个DataNode又把Packet输出到第二个DataNode中,以此类推;
5. DFSOutputStream还有一个对列叫Ack Quene,也是有Packet组成,等待DataNode的收到响应,当Pipeline中的全部DataNode都表示已经收到的时候,这时Akc Quene才会把对应的Packet包移除掉;
6. 客户端完成写数据后调用close()方法关闭写入流;
7. DataStreamer把剩余的包都刷到Pipeline里而后等待Ack信息,收到最后一个Ack后,通知NameNode把文件标示为已完成。
lhadoop fs
hadoop fs -ls /
hadoop fs -lsr
hadoop fs -mkdir /user/hadoop
hadoop fs -put a.txt /user/hadoop/
hadoop fs -get /user/hadoop/a.txt /
hadoop fs -cp src dst
hadoop fs -mv src dst
hadoop fs -cat /user/hadoop/a.txt
hadoop fs -rm /user/hadoop/a.txt
hadoop fs -rmr /user/hadoop/a.txt
hadoop fs -text /user/hadoop/a.txt
hadoop fs -copyFromLocal localsrc dst 与hadoop fs -put功能相似。
hadoop fs -moveFromLocal localsrc dst 将本地文件上传到hdfs,同时删除本地文件。
lhadoop fsadmin
hadoop dfsadmin -report
hadoop dfsadmin -safemode enter | leave | get | wait
hadoop dfsadmin -setBalancerBandwidth 1000
lhadoop fsck
lstart-balancer.sh
相关HDFS API能够到Apache官网进行查看:
在Hadoop集群中编译并运行《权威指南》中的例3.2,读取HDFS文件内容。
1 import java.io.InputStream; 2 3 import java.net.URI; 4 import org.apache.hadoop.conf.Configuration; 5 import org.apache.hadoop.fs.*; 6 import org.apache.hadoop.io.IOUtils; 7 8 public class FileSystemCat { 9 public static void main(String[] args) throws Exception { 10 String uri = args[0]; 11 Configuration conf = new Configuration(); 12 FileSystem fs = FileSystem. get(URI.create (uri), conf); 13 InputStream in = null; 14 try { 15 in = fs.open( new Path(uri)); 16 IOUtils.copyBytes(in, System.out, 4096, false); 17 } finally { 18 IOUtils.closeStream(in); 19 } 20 } 21 }
使用以下命令启动Hadoop
cd /app/hadoop-1.1.2/bin
./start-all.sh
在/app/hadoop-1.1.2目录下使用以下命令创建myclass和input目录:
cd /app/hadoop-1.1.2
mkdir myclass
mkdir input
进入/app/hadoop-1.1.2/input目录,在该目录中创建quangle.txt文件
cd /app/hadoop-1.1.2/input
touch quangle.txt
vi quangle.txt
内容为:
On the top of the Crumpetty Tree
The Quangle Wangle sat,
But his face you could not see,
On account of his Beaver Hat.
使用以下命令在hdfs中创建目录/class4
hadoop fs -mkdir /class4
hadoop fs -ls /
(若是须要直接使用hadoop命令,须要把/app/hadoop-1.1.2加入到Path路径中)
把例子文件上传到hdfs的/class4文件夹中
cd /app/hadoop-1.1.2/input
hadoop fs -copyFromLocal quangle.txt /class4/quangle.txt
hadoop fs -ls /class4
对/app/hadoop-1.1.2/conf目录中的hadoop-env.sh进行配置,以下如所示:
cd /app/hadoop-1.1.2/conf
sudo vi hadoop-env.sh
加入对HADOOP_CLASPATH变量值,值为/app/hadoop-1.1.2/myclass,设置完毕后编译该配置文件,使配置生效
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/app/hadoop-1.1.2/myclass
进入/app/hadoop-1.1.2/myclass目录,在该目录中创建FileSystemCat.java代码文件,命令以下:
cd /app/hadoop-1.1.2/myclass/
vi FileSystemCat.java
输入代码内容:
在/app/hadoop-1.1.2/myclass目录中,使用以下命令编译代码:
javac -classpath ../hadoop-core-1.1.2.jar FileSystemCat.java
ls
使用以下命令读取HDFS中/class4/quangle.txt内容:
hadoop FileSystemCat /class4/quangle.txt
在本地文件系统生成一个大约100字节的文本文件,写一段程序读入这个文件并将其第101-120字节的内容写入HDFS成为一个新文件。
注意:在编译前请先删除中文注释!
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileOutputStream; 4 import java.io.OutputStream; 5 import java.net.URI; 6 7 import org.apache.hadoop.conf.Configuration; 8 import org.apache.hadoop.fs.FSDataInputStream; 9 import org.apache.hadoop.fs.FileSystem; 10 import org.apache.hadoop.fs.Path; 11 import org.apache.hadoop.io.IOUtils; 12 import org.apache.hadoop.util.Progressable; 13 14 public class LocalFile2Hdfs { 15 public static void main(String[] args) throws Exception { 16 17 // 获取读取源文件和目标文件位置参数 18 String local = args[0]; 19 String uri = args[1]; 20 21 FileInputStream in = null; 22 OutputStream out = null; 23 Configuration conf = new Configuration(); 24 try { 25 // 获取读入文件数据 26 in = new FileInputStream(new File(local)); 27 28 // 获取目标文件信息 29 FileSystem fs = FileSystem.get(URI.create(uri), conf); 30 out = fs.create(new Path(uri), new Progressable() { 31 @Override 32 public void progress() { 33 System.out.println("*"); 34 } 35 }); 36 37 // 跳过前100个字符 38 in.skip(100); 39 byte[] buffer = new byte[20]; 40 41 // 从101的位置读取20个字符到buffer中 42 int bytesRead = in.read(buffer); 43 if (bytesRead >= 0) { 44 out.write(buffer, 0, bytesRead); 45 } 46 } finally { 47 IOUtils.closeStream(in); 48 IOUtils.closeStream(out); 49 } 50 }
进入/app/hadoop-1.1.2/myclass目录,在该目录中创建LocalFile2Hdfs.java代码文件,命令以下:
vi LocalFile2Hdfs.java
输入代码内容:
在/app/hadoop-1.1.2/myclass目录中,使用以下命令编译代码:
javac -classpath ../hadoop-core-1.1.2.jar LocalFile2Hdfs.java
进入/app/hadoop-1.1.2/input目录,在该目录中创建local2hdfs.txt文件
cd /app/hadoop-1.1.2/input/
vi local2hdfs.txt
内容为:
Washington (CNN) -- Twitter is suing the U.S. government in an effort to loosen restrictions on what the social media giant can say publicly about the national security-related requests it receives for user data.
The company filed a lawsuit against the Justice Department on Monday in a federal court in northern California, arguing that its First Amendment rights are being violated by restrictions that forbid the disclosure of how many national security letters and Foreign Intelligence Surveillance Act court orders it receives -- even if that number is zero.
Twitter vice president Ben Lee wrote in a blog post that it's suing in an effort to publish the full version of a "transparency report" prepared this year that includes those details.
The San Francisco-based firm was unsatisfied with the Justice Department's move in January to allow technological firms to disclose the number of national security-related requests they receive in broad ranges.
使用以下命令读取local2hdfs第101-120字节的内容写入HDFS成为一个新文件:
cd /app/hadoop-1.1.2/input
hadoop LocalFile2Hdfs local2hdfs.txt /class4/local2hdfs_part.txt
使用以下命令读取local2hdfs_part.txt内容:
hadoop fs -cat /class4/local2hdfs_part.txt
测试例子2的反向操做,在HDFS中生成一个大约100字节的文本文件,写一段程序读入这个文件,并将其第101-120字节的内容写入本地文件系统成为一个新文件。
1 import java.io.File; 2 import java.io.FileInputStream; 3 import java.io.FileOutputStream; 4 import java.io.OutputStream; 5 import java.net.URI; 6 7 import org.apache.hadoop.conf.Configuration; 8 import org.apache.hadoop.fs.FSDataInputStream; 9 import org.apache.hadoop.fs.FileSystem; 10 import org.apache.hadoop.fs.Path; 11 import org.apache.hadoop.io.IOUtils; 12 13 public class Hdfs2LocalFile { 14 public static void main(String[] args) throws Exception { 15 16 String uri = args[0]; 17 String local = args[1]; 18 19 FSDataInputStream in = null; 20 OutputStream out = null; 21 Configuration conf = new Configuration(); 22 try { 23 FileSystem fs = FileSystem.get(URI.create(uri), conf); 24 in = fs.open(new Path(uri)); 25 out = new FileOutputStream(local); 26 27 byte[] buffer = new byte[20]; 28 in.skip(100); 29 int bytesRead = in.read(buffer); 30 if (bytesRead >= 0) { 31 out.write(buffer, 0, bytesRead); 32 } 33 } finally { 34 IOUtils.closeStream(in); 35 IOUtils.closeStream(out); 36 } 37 } 38 }
进入/app/hadoop-1.1.2/myclass目录,在该目录中创建Hdfs2LocalFile.java代码文件,命令以下:
cd /app/hadoop-1.1.2/myclass/
vi Hdfs2LocalFile.java
输入代码内容:
在/app/hadoop-1.1.2/myclass目录中,使用以下命令编译代码:
javac -classpath ../hadoop-core-1.1.2.jar Hdfs2LocalFile.java
进入/app/hadoop-1.1.2/input目录,在该目录中创建hdfs2local.txt文件
cd /app/hadoop-1.1.2/input/
vi hdfs2local.txt
内容为:
The San Francisco-based firm was unsatisfied with the Justice Department's move in January to allow technological firms to disclose the number of national security-related requests they receive in broad ranges.
"It's our belief that we are entitled under the First Amendment to respond to our users' concerns and to the statements of U.S. government officials by providing information about the scope of U.S. government surveillance -- including what types of legal process have not been received," Lee wrote. "We should be free to do this in a meaningful way, rather than in broad, inexact ranges."
在/app/hadoop-1.1.2/input目录下把该文件上传到hdfs的/class4/文件夹中
hadoop fs -copyFromLocal hdfs2local.txt /class4/hdfs2local.txt
hadoop fs -ls /class4/
使用以下命令读取hdfs2local.txt第101-120字节的内容写入本地文件系统成为一个新文件:
hadoop Hdfs2LocalFile /class4/hdfs2local.txt hdfs2local_part.txt
使用以下命令读取hdfs2local_part.txt内容:
cat hdfs2local_part.txt