本章内容:
1.HDFS的由来和相关的概念
2.HDFS体系结构、HDFS存储原理、HDFS数据读写过程
3.HDFS编程实践
1.分布式文件系统HDFS简介
2.HDFS块的概念
现在可以把一个大的文件进行切割,可以把它切割成非常多的小块,这些小块可以分布式存储到不同的机器上面,这样就可以突破单机存储的上限。块的大小固定。块会备份
名称结点的启动—shell命令
Secondary Namenode属于备份的
3.HDFS体系结构
HDFS采用主从的架构,它有一个是主节点,其它是从节点,主节点起到管家作用,是一个数据目录服务。其它结点都是数据结点,负责具体的数据存储。
3.HDFS存储原理
伪分布式:把名称结点和数据结点都放在同一个机器上,这样的冗余只能是1(因为只有一台机器)
冗余存储的好处:
如果提交数据的请求不是来自集群内部,如果是集群外部某个节点发起的数据请求,那这个块要怎么放? HDFS应该怎么选?(数据的存放策略)
它会随机的挑选一台磁盘不太满,CPU又不太忙的结点,把它放置第一副本;第二副本我们会给它放在和第一副本不同的机架上面。第三副本,将它放在第一副本相同机架上的其它结点上
数据读取:
名称结点出错该怎么办?
数据结点出错该怎么办?
如何知道DataNode出错?
答:DataNode会隔一段时间给NameNode发送信息,如果NameNode没有收到DataNode发送的信息,则表示DataNode出错。
**数据本身出错怎么办?**通过校验码校验判断数据本身是否出错
4.HDFS数据读写
HDFS读数据过程:
HDFS写数据过程:
5.HDFS编程实践
5.1 HDFS常用命令
./bin/hdfs dfs -ls / :查看所有目录
./bin/hdfs dfs -mkdir /input :创建input文件夹
./bin/hdfs dfs -rm -r /input :删除input文件夹
cd ~ :进入家目录
vim myLocalFile.txt :在vim编辑器中,里面可以随意输入一些单词(输入i进入编辑状态;按ESC键退出编辑状态;输入:wq 保存文件并退出)
可以使用如下命令把本地文件系统的“/home/hadoop/myLocalFile.txt”上传到HDFS中的当前用户目录的input目录下,也就是上传到HDFS的“/user/hadoop/input/”目录下:
./bin/hdfs dfs -cp input/myLocalFile.txt /input :拷贝-cp
打开Linux自带的Firefox浏览器,点击此链接HDFS的Web界面,即可看到HDFS的web管理界面。WEB界面的访问地址是http://localhost:9870。
5.2 安装Eclipse
已安装(通过SecureCRT进行连接,SecureCrt是一款优秀的windows连接linux/unix机器的工具)
5.3 HDFS常用Java API及应用实例
Hadoop采用Java语言开发的,提供了Java API与HDFS进行交互。上面介绍的Shell命令,在执行时实际上会被系统转换成Java API调用。Hadoop官方网站提供了完整的Hadoop API文档(http://hadoop.apache.org/docs/stable/api/),想要深入学习Hadoop编程,可以访问Hadoop官网查看各个API的功能和用法。本教程只介绍基础的HDFS编程。
为了提高程序编写和调试效率,本教程采用Eclipse工具编写Java程序。
现在要执行的任务是:假设在目录“hdfs://localhost:9000/user/hadoop”下面有几个文件,分别是file1.txt、file2.txt、file3.txt、file4.abc和file5.abc,这里需要从该目录中过滤出所有后缀名不为“.abc”的文件,对过滤之后的文件进行读取,并将这些文件的内容合并到文件“hdfs://localhost:9000/user/hadoop/merge.txt”中。
**
cd /usr/local/eclipse :进入eclipse文件夹
./eclipse :启动eclipse软件
**
选择“File–>New–>Java Project”菜单,开始创建一个Java工程,会弹出如下图所示界面。
选中lib下的所有jar包
下面进入第3次导入jar包
下面进入第4次导入jar包
以上共点击4次jar包,导入完成所有操作
然后进入eclipse软件中
将代码复制后粘贴进Eclipse中
import java.io.IOException;
import java.io.PrintStream;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
/**
* 过滤掉文件名满足特定条件的文件
*/
class MyPathFilter implements PathFilter {
String reg = null;
MyPathFilter(String reg) {
this.reg = reg;
}
public boolean accept(Path path) {
if (!(path.toString().matches(reg)))
return true;
return false;
}
}
/***
* 利用FSDataOutputStream和FSDataInputStream合并HDFS中的文件
*/
public class MergeFile {
Path inputPath = null; //待合并的文件所在的目录的路径
Path outputPath = null; //输出文件的路径
public MergeFile(String input, String output) {
this.inputPath = new Path(input);
this.outputPath = new Path(output);
}
public void doMerge() throws IOException {
Configuration conf = new Configuration();
conf.set("fs.defaultFS","hdfs://localhost:9000");
conf.set("fs.hdfs.impl","org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fsSource = FileSystem.get(URI.create(inputPath.toString()), conf);
FileSystem fsDst = FileSystem.get(URI.create(outputPath.toString()), conf);
//下面过滤掉输入目录中后缀为.abc的文件
FileStatus[] sourceStatus = fsSource.listStatus(inputPath,
new MyPathFilter(".*\\.abc"));
FSDataOutputStream fsdos = fsDst.create(outputPath);
PrintStream ps = new PrintStream(System.out);
//下面分别读取过滤之后的每个文件的内容,并输出到同一个文件中
for (FileStatus sta : sourceStatus) {
//下面打印后缀不为.abc的文件的路径、文件大小
System.out.print("路径:" + sta.getPath() + " 文件大小:" + sta.getLen()
+ " 权限:" + sta.getPermission() + " 内容:");
FSDataInputStream fsdis = fsSource.open(sta.getPath());
byte[] data = new byte[1024];
int read = -1;
while ((read = fsdis.read(data)) > 0) {
ps.write(data, 0, read);
fsdos.write(data, 0, read);
}
fsdis.close();
}
ps.close();
fsdos.close();
}
public static void main(String[] args) throws IOException {
MergeFile merge = new MergeFile(
"hdfs://localhost:9000/user/hadoop/",
"hdfs://localhost:9000/user/hadoop/merge.txt");
merge.doMerge();
}
}
在编译运行程序之前,我们一定要保证Hadoop已经启动运行,没有启动一定要启动运行
注意:这里需要重新打开一个新的终端,如果停掉那个Eclipse就会关掉Eclipse。
修改文件的名字: mv file4.txt file4.abc
进行访问file2文件中的内容:cat file2.txt
**使用put 命令可以把本地的文件上传到我们远程文件夹中:./bin/hdfs dfs -put ./file1.txt /user/hadoop
**
运行